I have a function downloading JSON. It does it fine however in some cases a object may not contain a certain key. On that occasion it still trys to add a value to the array. I want to make it so if the key is not present then a value of nil is added to the array. Would appreciate it if someone could help. Thanks alot.
if let link = itemDict.value(forKey: "link") {
if link != nil {
self.linkArray.append(link as! String)
}
}
Just do not use the force unwrapping. Also your if let is wrong for what you want to achieve. Copy paste version:
let link = itemDict.value(forKey: "link") as? String
self.linkArray.append(link)
Related
I am trying to make a weather app. the issue I am having is after I get the data parsed out I try to change the UILabel to equal the data that came back example.
if let weather = item["weather"] as? NSArray{
if let value = weather[0] as? NSDictionary{
if let description = value["description"] as? String{
print(description)
}
instead of printing the description I want to change the content of the UI Label like this
conditionlabel.text = description
but I get this error Reference to property 'Condition' in closure requires explicit 'self.' to make capture semantics explicit.
however, every time I try the self. in front it does not print my data and something else happens. Any help would be much appreciated as I am new to this
Create an optional variable in controller that has you UILabel:
var descriptionText: String?
Now when you parse data, assign value to this variable
if let description = value["description"] as? String{
descriptionText = description
}
After data is parsed assign this value to the label
self.conditionlabel.text = descriptionText
I think what you need to do here is use self.conditionlabel.text = description (that is, the use of self is for the UILabel rather than description - my guess is that you were using self.description which gives you a description of the view controller.)
EDIT:
To overcome the threading issue, wrap the code like this:
DispatchQueue.main.async { [weak self] in
self?.conditionlabel.text = description
}
Okay I am reading from a database and when I print the individual variables they print out correctly. However it seems like the data refuses to append to the array. Anyone know why? I can't figure it out at all.
let commuteBuilder = Commutes()
Database.database().reference().child("Users").child(user).child("Trips").observe(DataEventType.childAdded, with: { (snapshot) in
//print(snapshot)
if let dict = snapshot.value as? NSDictionary {
commuteBuilder.distance = dict["Distance"] as! Double
commuteBuilder.title = dict["TripName"] as! String
commuteBuilder.transportType = (dict["Transport"] as? String)!
}
commuteArray.append(commuteBuilder)
})
print("helper")
print(commuteArray.count)
return commuteArray
The data is correctly added to the array, just not at the time that you print the array's contents.
If you change the code like this, you can see this:
let commuteBuilder = Commutes()
Database.database().reference().child("Users").child(user).child("Trips").observe(DataEventType.childAdded, with: { (snapshot) in
if let dict = snapshot.value as? NSDictionary {
commuteBuilder.distance = dict["Distance"] as! Double
commuteBuilder.title = dict["TripName"] as! String
commuteBuilder.transportType = (dict["Transport"] as? String)!
}
commuteArray.append(commuteBuilder)
print("added one, now have \(commuteArray.count)")
})
print("returning \(commuteArray.count)")
return commuteArray
You'll see it print something like this:
returning 0
added one, now have 1
added one, now have 2
etc.
This is likely not the output you expected. But it is working as intended. Firebase loads data from its database asynchronously. Instead of blocking your code, it lets the thread continue (so the user can continue using the app) and instead calls back to the code block you passed to observe when new data is available.
This means that by the time this code returns the array it is still empty, but it later adds items as they come in. This means that you cannot return data from a function in the way you are trying.
I find it easiest to change my way of thinking about code. Instead of "First get the data, then print it", I frame it as "Start getting the data. When data comes back, print it".
In the code above, I did this by moving the code that prints the count into the callback block. Instead of doing this, you can also create your own callback, which is called a completion handler or closure in Swift. You can find examples in this article, this article, this question Callback function syntax in Swift or of course in Apple's documentation.
I converted a JSON to Dictionary and got some String by
title = json?.objectForKey("Titel_Live") as! String
But some times app will be crashed. I cannot reproduce this problem, just get information from crash reports.
Could someone help me and tell why? Thanks
Error at line 163
Crash reports
title = json?.objectForKey(“Titel_live”) as! String
This line of code where you are doing force unwrapped (Don't force the cast using !) is the cause means if object with key Titel_live dot not find then should be crashed, better go with optional chaining or use gaurd but yes your Json does't contain any object with key Titel_live(may be spelling mistake or object is array so validate once).
//better go like this check if exist or not.
if let t = json?.objectForKey(“Titel_live”) {
title = t
}
You should not force the casting to String.
You can try :-
title = json?.objectForKey("Title_Live") as? String (if title is optional variable)
if title is not optional then use:
title = (json?.objectForKey("Title_Live") as? String ?? "")
Because objectForKey will return nil if no value is associated with that key and force casting nil to String fails and causes crash.
When I am trying to take the value from a plist and append it to an array
nameArray.append(namesArray!.objectForKey("Item1")! as! String)
The target item is a string but it appears to be inside the plist array, can anyone explain how to get it out please?
The print of namesArray!.objectForKey("Item1")! followed by the error are shown below:
Cast the value of the "Item1" key as an array of Strings, then fetch the first object from the array (since it appears there's only one). And if you like the idea that your app should not crash everytime a value is nil, better use if let than force-unwrapping everything with !.
Example:
if let names = namesArray,
let items = names.objectForKey("Item1") as? [String],
let result = items.first {
nameArray.append(result)
}
Just take the first element of your array:
nameArray.append((namesArray!.objectForKey("Item1")! as! [String])[0])
I am trying to get an array from a Parse.com database in my Swift app. For some reason, the array returned is always nil. I checked the permissions to make sure that the data can be accessed by my app, I find it really hard to find a starting point for this bug.
Here's my code:
let username = PFUser.currentUser()?.objectId
print("username: \(username)")
let bannedUsers = PFUser.currentUser()!["bannedUsers"] as? NSArray
print("bannedUsers: \(bannedUsers)")
The log output:
username: Optional("Nmmtb07PoR")
bannedUsers: nil
A screenshot from the database to show the array is not nil:
The exact value of the array:
[{"__type":"Pointer","className":"_User","objectId":"mG33sM3fcC"}]
I tried playing around with the contents of the array, but no matter what I put in it, whether it's a pointer or just a string, I always get 'nil'. I hope you can help.
Solved:
I added the line
PFUser.currentUser()?.fetch()
This refreshed the user and I got the proper data instead of 'nil'. Hope it helps if you have a similar issue in the future.
How about:
let bannedUsers = PFUser.currentUser()!.bannedUsers as? NSArray
Try using: PFUser.currentUser()!.objectForKey("bannedUsers")
or PFUser.currentUser()!.valueForKey("bannedUsers")
Your column could be not included in the currentUser object so you would have to query users and include the bannedUsers column.
You can do it by the following:
let query = PFUser.query()
query?.includeKey("bannedUsers")
do {
let user = try query?.getObjectWithId((PFUser.currentUser()?.objectId)!)
let bannedUsers = user?.valueForKey("bannedUsers")
print(bannedUsers)
} catch {
print(error)
}