Swift: Changing value of global variable via function. - arrays

I'm trying to change the value of a global variable transferredData in the function didTransferData(_ data: Data?). My code looks like this:
var transferredData: [Double] = [0.0]
func didTransferData(_ data: Data?) {
var dataArray = [CUnsignedChar](repeating:0, count: (data?.count)!)
data?.copyBytes(to: &dataArray, count: dataArray.count)
let dataInt = dataArray.filter({ Int(String($0)) != nil }).map({ Int(String($0))! })
let dataDouble = dataInt.map { Double($0) }
print("Data double: \(dataDouble)")
transferredData = dataDouble
}
Printing transferredData inside of didTransferData returns the correct array, containing all values of dataDouble. But when I try to access it in this function later on
func returnData() -> [Double]{
print("return Data: \(transferredData)")
return transferredData
}
it returns [0.0]. I'm not sure if I'm missing something crucial here, but I thought that even if I change the value of a global variable in a function, the new value should be accessible for every other functions, too.
Thanks for any advice!!

You said that this code is inside a class. The variable transferredData is not a global, it is a member variable.
There is one of these per object of the class. I suspect that you are not using the same object to make these two calls.
You could make the member shared between all objects by declaring it static, but I think it would be better to leave as is and arrange to use the same object.
EDIT: based on comment
If you write the code
let centralInstance = CentralViewController()
You will get a new object with its own transferredData member initially set to [0.0]. You need to either
Get a reference to the same VC object that has the data
Store the data some where else in an object that you can get back (since the VC might be gone)
To hack something that works (not recommended, but to help understand)
You could move transferredData out of the class and make it an actual global variable. I would do this only to help you get past this issue and understand what's going on.
You could also make it static, which makes all of the VC's share the same instance of the transferredData
When you understand what is going on, you can try to do something a little better (at least move it to its own model object, and not in the VC at all). The next simplest thing is some kind of singleton to manage it -- this is just a glorified global variable but puts you more on the road to a more typical solution.

Where is the problem:
$ swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
1> var data:[Double] = [0.0]
2.
3. class MuckWithData {
4.
5. func showData () -> [Double] {
6. print ("Data: \(data)")
7. return data
8. }
9.
10. func modifyData () {
11. data = [1.0]
12. }
13. }
data: [Double] = 1 value {
[0] = 0
}
14>
15> var mucked = MuckWithData()
mucked: MuckWithData = {}
16> mucked.showData()
Data: [0.0]
$R0: [Double] = 1 value {
[0] = 0
}
17> mucked.modifyData()
18> mucked.showData()
Data: [1.0]
$R1: [Double] = 1 value {
[0] = 1
}
Probably your computation for dataDouble is actually [0.0] and thus it appears that transferredData didn't change, but it did.

Related

SWIFT still fighting to assign a value to a nested array within a class

This carries on my last question struggling with value assignment to optional class variable, for which David provided me a good hint to a similar problem.
After numerous iterations I now came up with a different approach, however, it still fails and I have no idea why (and basically what happens)
I have the class definitions
struct HighScores: Codable {
var Scores:Int
var highscoreRecord: [HighscoreRecord]
}
struct HighscoreRecord: Codable {
var Rank:Int
var Date:String?
var avDuration:Float?
var Score:Int?
var Tries:Int?
}
In the view controller I have declared a variable of type HighScores, which may read the data from a JSON file or which may be initialized when setting the first high score.
class GameplayViewController: UIViewController {
var jsonResult: HighScores?
...
if firstHighscore == 1 {
jsonResult?.Scores = 1
jsonResult?.highscoreRecord.append(HighscoreRecord(Rank: 1, Date: formatter.string(from: dateStart), avDuration: Float(lblSpeed.text ?? "0.0"), Score: Int(lblRatio.text ?? "0"), Tries: hits + misses))
...
print(jsonResult)
This compiles and also runs. However, if I monitor the jsonResult variable, it still shows nil after assigning the Scores and and highscoreRecord values.
What happens, why can I assign a value without an error and without actually assigning it?
And first and foremost, how do I get my values into jsonResult?
Cheers
So following on from the comments above if you changed the code to be something along the lines of this you create the instance of the struct and add the values.
var jsonResult: HighScores?
if firstHighscore == 1 {
jsonResult = HighScores(Scores: 1, highscoreRecord: [HighscoreRecord(Rank: 1, Date: "your date", avDuration: 0.0, Score: 0, Tries: 0)])
}
once created you can add more highscorerecords to the array as needed, using the append method.

godot invalid get index '-1'(on base 'array') during A.P.I

I'm making an A.P.I. that displays dialogue, choices, sprites, audio etc. etc., i was able to do it after looking up this video on youtube but i keep getting this error invalid get '-1' (on base 'array') here's my code so you can see
extends Control
onready var bg_rect = get_node("Media_Sys/BG_Rect")
onready var char_sprite = get_node("Media_Sys/Sprite")
onready var text_box = get_node("Dialog_Sys/Dialog_Text")
onready var text_nam = get_node("Dialog_Sys/Label/Name")
onready var click = get_node("ClickManager")
var player = []
var lu = "Lu"
var ciel = "Ciel"
func _ready():
click.request_ready()
func write(char_name_str, text_str=null):
if text_str == null:
text_str = char_name_str
char_name_str = ""
player.push_front({"type": "dialogue","name": char_name_str, "text": text_str})
func write_component():
text_nam.clear()
text_box.clear()
text_nam.add_text(player[player.size() - 1]["name"])#the debugger says the problem is here
text_box.add_text(player[player.size() - 1]["text"])#as well as here if you remove the first line.
player.pop_back()
func _input(event):
if event is InputEventMouseButton:
write_component()
I have some people say that it's because i didn't define the size of the array, i have some people say that it's really weird that my code somehow set the player as an integer. I've check the array docs page for this and came up with nothing, I've changed some minor things in the code but it still churns out the same invalid error.
extends Node
onready var g = get_parent()
var lu = "Lu"
var ciel = "Ciel"
func _ready():
g.write(lu, "hello")
One thing to note is that it does display the dialogue and name, i just get the error immediantly afterwards.
You initialize the player variable to be an empty list. Then, in write_component you attempt to access this list with the calculated index [player.size() - 1]. The issue is that if player is empty, this ends up as [0-1] or [-1] as an index, which is not valid in GDScript. Your code assumes Write will be called first (and it may, some of the time) so that player is not empty by the time write_component is called.
The most immediate solution is to check if player.size() == 0 before attempting to access the last element.
func write_component():
text_nam.clear()
text_box.clear()
if player.size() > 0:
text_nam.add_text(player[player.size() - 1]["name"])
text_box.add_text(player[player.size() - 1]["text"])
player.pop_back()

Simple swift array append not working

I know this is going to be super elementary, but I have this piece of code:
var labels: [String]?
func initVC(image: Images){
self.image = image
let tempLabels = image.label?.allObjects as! [Labels]
for i in 0..<tempLabels.count{
labels?.append(tempLabels[i].label!)
}
}
labels is in the public scope, so the function should have access to it, but when the loop runs through, labels is still nil with no elements.
When I po during debugging, tempLabels is as I expect it to be with 2 string elements.
I'm pretty sure this is a very simple problem, but I guess I'm just out of it right now.
Labels has never been initialised. Change
var labels:[String]?
to
var labels:[String] = []
You are declaring the labels variable but never allowing it to store information. This means that it does not necessarily exist, since it is not initialized, and therefore cannot be used.
For it to be useable, you must initialize it
var labels:[String] = []
Yep, it was super simple.
Changed
var labels: [String]?
To
var labels = [String]()

circular reference using weak variables causing the unwrapping of nils

let me start off by saying I searched to find a topic that would help me but I could not anything that helped. Here is my situation...
I created a class sign where I created the variable thing1. I then created an array called arrayX that uses sign. Then I used a NSURL session to pull values from a domain. I then created thingX that will hold that value and finally I appended my arrayX with that value of thingX. This works GREAT except that it appears i have strong circular references and the memory cannot be deallocated. I tried fixing it with weak references but then the occasional empty thingX causes my app to crash because it is trying to unwrap a nil. Please help!!!
class sign {
var thing1 = ""
init(thing1: String) {
self.thing1 = thing1
}
}
var arrayX : [sign] = [sign]()
index1 = 0
while index1 < count {
//NSURL will grab info info will grab a value from my domain and thingX will be given this value (occasionally the value will be empty)
let thingX = ‘NSURL value’ as! String
let data1 = sign(thing1: thingX)
self.arrayX.append(data1)
index1++
}

Modifying an array of dictionaries in Swift

I’m new to Swift and have been having some troubles figuring out some aspects of Arrays and Dictionaries.
I have an array of dictionaries, for which I have used Type Aliases - e.g.
typealias myDicts = Dictionary<String, Double>
var myArray : [myDicts] = [
["id":0,
"lat”:55.555555,
"lng”:-55.555555,
"distance":0],
["id":1,
"lat": 44.444444,
"lng”:-44.444444,
"distance":0]
]
I then want to iterate through the dictionaries in the array and change the “distance” key value. I did it like this:
for dict:myDicts in myArray {
dict["distance"] = 5
}
Or even specifically making sure 5 is a double with many different approaches including e.g.
for dict:myDicts in myArray {
let numberFive : Double = 5
dict["distance"] = numberFive
}
All my attempts cause an error:
#lvalue $T5' is not identical to '(String, Double)
It seems to be acting as if the Dictionaries inside were immutable “let” rather than “var”. So I randomly tried this:
for (var dict:myDicts) in myArray {
dict["distance"] = 5
}
This removes the error and the key is indeed assigned 5 within the for loop, but this doesn't seem to actually modify the array itself in the long run. What am I doing wrong?
The implicitly declared variable in a for-in loop in Swift is constant by default (let), that's why you can't modify it directly in the loop.
The for-in documentation has this:
for index in 1...5 {
println("\(index) times 5 is \(index * 5)")
}
In the example above, index is a constant whose value is automatically
set at the start of each iteration of the loop. As such, it does not
have to be declared before it is used. It is implicitly declared
simply by its inclusion in the loop declaration, without the need for
a let declaration keyword.
As you've discovered, you can make it a variable by explicitly declaring it with var. However, in this case, you're trying to modify a dictionary which is a struct and, therefore, a value type and it is copied on assignment. When you do dict["distance"] = 5 you're actually modifying a copy of the dictionary and not the original stored in the array.
You can still modify the dictionary in the array, you just have to do it directly by looping over the array by index:
for index in 0..<myArray.count {
myArray[index]["distance"] = 5
}
This way, you're sure to by modifying the original dictionary instead of a copy of it.
That being said, #matt's suggestion to use a custom class is usually the best route to take.
You're not doing anything wrong. That's how Swift works. You have two options:
Use NSMutableDictionary rather than a Swift dictionary.
Use a custom class instead of a dictionary. In a way this is a better solution anyway because it's what you should have been doing all along in a situation where all the dictionaries have the same structure.
The "custom class" I'm talking about would be a mere "value class", a bundle of properties. This was kind of a pain to make in Objective-C, but in Swift it's trivial, so I now do this a lot. The thing is that you can stick the class definition for your custom class anywhere; it doesn't need a file of its own, and of course in Swift you don't have the interface/implementation foo to grapple with, let alone memory management and other stuff. So this is just a few lines of code that you can stick right in with the code you've already got.
Here's an example from my own code:
class Model {
var task : NSURLSessionTask!
var im : UIImage!
var text : String!
var picurl : String!
}
We then have an array of Model and away we go.
So, in your example:
class MyDict : NSObject {
var id = 0.0
var lat = 0.0
var lng = 0.0
var distance = 0.0
}
var myArray = [MyDict]()
let d1 = MyDict()
d1.id = 0
d1.lat = 55.55
d1.lng = -55.55
d1.distance = 0
let d2 = MyDict()
d2.id = 0
d2.lat = 44.44
d2.lng = -44.44
d2.distance = 0
myArray = [d1,d2]
// now we come to the actual heart of the matter
for d in myArray {
d.distance = 5
}
println(myArray[0].distance) // it worked
println(myArray[1].distance) // it worked
Yes, the dictionary retrieved in the loop is immutable, hence you cannot change.
I'm afraid your last attempt just creates a mutable copy of it.
One possible workaround is to use NSMutableDictionary:
typealias myDicts = NSMutableDictionary
Have a class wrapper for the Swift dictionary or array.
class MyDictionary: NSObject {
var data : Dictionary<String,Any>!
init(_ data: Dictionary<String,Any>) {
self.data = data
}}
MyDictionary.data

Resources