circular reference using weak variables causing the unwrapping of nils - arrays

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++
}

Related

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()

Swift: Changing value of global variable via function.

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.

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

Found nil while unwrapping an Optional value (Music Library)

var songList = NSMutableArray()
var player = AVPlayer()
var isSelected = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var songs = MPMediaQuery() // also tried var songs = MPMediaQuery.songsQuery()
var localSongs: NSArray = songs.items
songList = NSMutableArray(array: localSongs)
tableView.reloadData()
var song: MPMediaItem = songList[0] as MPMediaItem // <<- Error here
var currentItem = AVPlayerItem(URL: song.valueForProperty(MPMediaItemPropertyAssetURL) as NSURL)
player.replaceCurrentItemWithPlayerItem(currentItem)
player.play()
var songTitle: NSString = song.valueForProperty(MPMediaItemPropertyTitle) as NSString
songName.text = songTitle
var time = Float(CMTimeGetSeconds(player.currentItem.duration))
sliderOutlet.value = time
}
I'm building a music player, but the app crasher when i run in the simulator and gives this error: index 0 beyond bounds for empty array, and says this when i try run on iPhone : {
MediaLibrary} Database validation succeeded
fatal error: unexpectedly found nil while unwrapping an Optional value
EDIT: Seems like it's not accessing the local music library on my iPhone and adding songs to the array.
You're accessing an element without testing its size. So songList[0] is out of bounds, hence the crash.
If your media query returns no items, then localSongs and songlist will both be arrays of size 0. When you then try to reference a song with songList[0] you will be accessing index 0 in an empty array. Hence the crash.
Seems more like a problem with expecting the simulator to have music in it. Since it doesn't, songList.count == 0, which means songList[0] should generate an exception. Seems like the expected and desired behavior to me.
Put a check on count using if condition. You are accessing index which can be nil. If accessed it will through runtime error.
Preferred approach would it be wrapped explicitly with ?

swift setting string from array element error

So im grabbing a property from core data, using a dictionary. And it grabs it just fine. However, when I try to take that single returned attribute and assign it to the navigationitem.title it throws some nasty error. Am I missing something here..
Its not actually outputting an error message in the console but instead is giving me this:
Thread 1: EXC_BREAKPOINT(code+exc_I386_BPT.....
on this line.
0x10707a5f3: nopw %cs:(%rax,%rax)
Also its saying
0 swift_dynamicCastObjCClassUnconditional
code:
override func viewDidLoad() {
super.viewDidLoad()
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext
let frequest = NSFetchRequest(entityName: "Round")
frequest.propertiesToFetch = NSArray(object: "course")
frequest.returnsObjectsAsFaults = false
frequest.returnsDistinctResults = true
frequest.resultType = NSFetchRequestResultType.DictionaryResultType
var fetchedArray = context.executeFetchRequest(frequest, error: nil)
//this is the line that throw the error...why won't it let me set the title to the array of the single returned result?
self.navigationItem.title = fetchedArray[0]
println(fetchedArray)
}
Without a specific error message you are receiving, this is just a guess...
NSArray un untyped contents (that is to say that elements are of type AnyObject), so the compiler probably doesn't think you can set AyObject as a string. So likely need something like:
self.navigationItem.title = fetchedArray[0] as String
Or:
self.navigationItem.title = String(fetchedArray[0])
To start, I would check couple of things to see if the problem is in the fetched array or in the navigation item:
what exactly is returned in fetchedArray[0]? Is is a string? A nil? Something else? Does it actually have anything at index 0? After checking if fetchedArray is not nil and has any elements, you could use "\(fetchedArray[0])"
What is the state of navigationItem? Is it actually instantiated at the time you are trying to set it's title property? I would suggest checking it for nil. You can also try assigning it a string like this: self.navigationItem.title = "Hello" and see if it fails.

Resources