Everything works swimmingly except for when I do a random string like "fds", how would I correctly and efficiently use a guard to protect from this sort of error?
init(weatherData: [String: AnyObject]) {
city = weatherData["name"] as! String
let weatherDict = weatherData["weather"]![0] as! [String: AnyObject]
description = weatherDict["description"] as! String
icon = weatherDict["icon"] as! String
let mainDict = weatherData["main"] as! [String: AnyObject]
currentTemp = mainDict["temp"] as! Double
humidity = mainDict["humidity"] as! Int
let windDict = weatherData["wind"] as! [String: AnyObject]
windSpeed = windDict["speed"] as! Double
}
how would I correctly and efficiently use a guard to protect from this sort of error?
Why would you want to? If the caller does not hand you a dictionary whose "name" key is present and is a string, you are dead in the water because you cannot initialize city. You want to crash.
If you would like to escape from this situation without actually crashing, then make this a failable initializer and fail (return nil) if the dictionary doesn't contain the needed data. This effectively pushes the danger of crashing onto the caller, because the result will be an Optional that might be nil, and the caller must check for that.
init?(weatherData: [String: AnyObject]) {
guard let city = weatherData["name"] as? String else {return nil}
self.city = city
// ... and so on ...
}
But what I would do is none of those things. I would rewrite the initializer as init(city:description:icon:currentTemp:humidity:windSpeed:) and force the caller to parse the dictionary into the needed data. That way, if the data is not there, we don't even try to initialize this class in the first place. My argument would be that it is the caller's job to parse the dictionary; this class should have no knowledge of the structure of some complex dictionary pulled off the Internet (or whatever the source is).
Related
I am trying to develop followers for an app. Here is the code I have to retrieve the current authenticated users (minus the logged in user) and create a local list. I also have code to write a followers list to the Firebase but just this code (step 1) is throwing errors.
func retrieveUsers() {
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: {snapshot in
let users = snapshot.value as! [String: AnyObject]
self.user.removeAll()
for (_, value) in users {
if let uid = value["uid"] as! String {
if uid != Auth.auth().currentuser.uid {
let userToShow = User()
if let firest_name = value["firest_name"] as? String {
userToShow.userId = uid
self.user.append(userToShow)
}
}
}
}
self.tableView.reloadData()
})
}
if let uid = value["uid"] as! String {
is throwing Ambiguous use of 'subscript(_:)' which I really do not understand. Any help is appreciated!
You're casting your users constant to type [String: AnyObject]. In the loop where you're iterating the dictionary you try to create a constant uid assuming that value is a dictionary with String keys. However you don't know that since it is AnyObject as per your previous cast. AnyObject doesn't respond to subscript(_:) hence your error.
If you know that snapshot.value is indeed a [String: Dictionary] then you can change your cast type or you could cast value to this type.
Also note that using a force cast is a bad practice and can lead to nasty and hard to find bugs.
` let query = ref?.child("Reviews").queryOrdered(byChild: "UserID").queryEqual(toValue: myUser.userId)
query?.observeSingleEvent(of: .value) { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let uid = dict["UserID"] as! String
let review = dict["Body"] as! String
let rating = dict["Rating"] as! String
let titleID = dict["TitleID"] as! String
let reviewID = dict["ReviewID"] as! String
let ratingID = dict["RatingID"] as! String
`
THE ERROR OCCURS AT THE ratingID call to the database. It unwraps nil.
I am trying to adapt a pre existing Firebase database with a new key/value.
I then try to display entries in my tableview and I get a crash with unwrap returning nil. I know why this is happening and it's because the previous data does not have the new key/value I want to include in the node going forward. I have tried many different things such as if let and guard let without much fortune. How do I add new key/Values and still have the tableview read entries that don't have the new value?
I include an image of the current node and I want to add a 'RatingsID' to the node. When I do, I get the unwrap nil error.
Database node prior to new key/value
Your code is super close, just need to protect the code in case the ratingID key doesn't exist.
So change
let ratingID = dict["RatingID"] as! String
to
let ratingID = dict["RatingID"] as! String ?? ""
So if the RatingID node does not exist, you'll set ratingID to an empty string (or whatever string you want)
You could also code it to only operate on the value of that key if the node exists (not nil)
if let someVal = dict["xxx"] {
//do something with someVal
} else {
print("xxx node wasn't found")
}
Here's a complete example: We are reading some messages from the messages node and some of them have a test_key node and some dont. For those that don't, default string is assigned to test
let postsRef = self.ref.child("messages")
postsRef.observe(.childAdded) { snapshot in
let dict = snapshot.value as! [String: Any]
let msg = dict["msg"] as! String
let test = dict["test_key"] ?? "default string"
print(msg, test)
}
So I am currently working on a personal project to help understand API's and how they work..so I am still a little new to iOS Development. I have already connected to the URL and gotten the data however now I am trying to make the results a little bit more clear cut.
Below is the code for the class (when the button is clicked it prints all this information)
First part of code
Second part of code
The error I get is Type 'Any' has no subscript members. Any idea as to why? Or how this can be fixed?
you can set their types like this then you can print values.
if let main = json["main"] as? [String: Any] {
let temp = main["temp"] as? Double
print("temp\(temp!)")
let temp_max = main["temp_max"] as? Double
print("temp\(temp_max!)")
let temp_min = main["temp_min"] as? Double
print("temp\(temp_min!)")
}
let items = json["weather"] as! [AnyObject]
let main = items[0]["main"] as! String
print(main)
let description = items[0]["description"] as! String
print(description)
let icon = items[0]["icon"] as! String
print(icon)
let name = json["name"] as! String
print("name\(name)")
So I'm trying to retrieve only the "second" value of a child from my firebase database.
The structure looks like this:
And what I'm getting as an output is this:
However what I actually want is just:
someURL.com
Ideally even without the https or http (where I probably need an if to check, since it is not known for all of them in advance). I guess there are 2 options, either unwrapping the string in Swift, or (what I was hoping for) just retrieving the actual value without the brackets and "url" in the beginning. I couldn't find a similar problem on here yet.
My code for retrieving:
dataSource?.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FIRDataSnapshot
let childString = snap.value as! [String : AnyObject]
cell.textLabel?.text = String(childString)
}
Try this
dataSource?.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FIRDataSnapshot
let childString = snap.value as! [String : AnyObject]
if let url = childString["url"] as? String {
cell.textLabel?.text = url
} else {
print("No value for url")
}
}
childString variable you are using is a dictionary which has values for keys. You need to fetch the value for the key "url".
I am using the following code to get data from an API:
typealias JSONdic = [String: AnyObject]
if let json = json as? JSONdic, history = json["history"] as? JSONdic, hour = history["hour"] as? String {
println(hour)
}
However, Xcode tells me that "json" is not a recognized identifier. I believe this can be solved with NSURLConnection, but I have no idea how to use that. Can anyone provide any examples of this protocol in use?
You're declaring a variable by setting it to itself, which doesn't make any sense. In order to use a variable on the right hand side of an assignment, it needs to have already been declared. So let's give json a value outside of the casting statements and it works fine.
typealias JSONdic = [String: AnyObject]
let json: AnyObject = ["greeting": "Hello"]
if let json = json as? JSONdic, history = json["history"] as? JSONdic, hour = history["hour"] as? String {
println(hour)
}