I have the following code
if let unwrappedDict = snapshot.value as? NSDictionary {
for (index, dd) in unwrappedDict {
let dd = dd as? NSDictionary ?? [:]
id = dd["id"] as? String ?? ""
let ccode = dd["code"] as? String ?? ""
if (ccode == code) {
if id.count > 0 {
found = true;
}
}
}
}
How can I make this code better? I'm specifically talking about this line let dd = dd as? NSDictionary ?? [:]?
You can make the code more compact, Swift-like and functional by doing something like this:
let found = (snapshotValue as? NSDictionary)?.compactMap { $1 as? NSDictionary }.contains { $0["code"] as? String == ccode && ($0["id"] as? String)?.isEmpty == false } ?? false
Explaining piece by piece:
(snapshotValue as? NSDictionary)?.compactMap { $1 as? NSDictionary } // This tries to cast snapshotValue as an NSDictionary, and only if that succeeds, takes the array of (key, value)'s from the dictionary and tries to cast each value as an NSDictionary. The output of this segment is an array of only values that succeeded in being cast to NSDictionary.
.contains { $0["code"] as? String == ccode && ($0["id"] as? String)?.isEmpty == false } // In the array of NSDictionary values that are also NSDictionaries themselves, check if any of those child dictionaries meet the condition of having the right code and a non-empty id string. If any one of them do, return true and early exit the loop
?? false // If the original conditional cast of snapshotValue as? NSDictionary fails, return false for the value found
Related
I'm updating my code from Swift 2.3 to Swift 3, and I am facing these difficulties to get an array key value from a loop in Swift:
var countryarray = NSMutableArray()
self.GetCountriesResult = (responseJSON.objectForKey("GetCountriesResult") as? NSArray)!
for i in 0 ..< self.GetCountriesResult.count {
self.countryarr = self.GetCountriesResult.objectAtIndex(i).objectForKey("countryname") as? String ?? ""
self.countryarray.addObject(self.countryarr)
}
map is better suited than for-in in this case:
guard let json = responseJSON["GetCountriesResult"] as? [String : AnyObject]
else { return }
self.GetCountriesResult = json
let countryArray = self.GetCountriesResult.map {
return $0["countryname"] as? String ?? ""
}
// OR
guard let json = responseJSON["GetCountriesResult"] as? [String : AnyObject]
else { return }
let countries = json.map {
return $0["countryname"] as? String ?? ""
}
Suggestion: Read the following Swift style guides:
https://swift.org/documentation/api-design-guidelines/
https://github.com/raywenderlich/swift-style-guide
https://github.com/linkedin/swift-style-guide
https://github.com/github/swift-style-guide
I have a firebase database in my app, here is a screenshot of it:
And I need to filter my results using this controller
so I need to compare from
`ref.observe(.value, with: {snapshot in
if (snapshot.value is NSNull){
print("not found")
}else{
for child in (snapshot.children) {
let snap = child as! DataSnapshot
let dict = snap.value as! AnyObject
let latt = dict["lat"]
let lngt = dict["lng"]
let sext = dict["sex"]
let statust = dict["status"]
let aget = dict["age"]
if self.searchSex.selectedSegmentIndex == 0{
self.sexG = "Male"}
else if self.searchSex.selectedSegmentIndex == 1{
self.sexG = "Female"
}
if (self.sexG == sext as! String && Int(searchAgeFrom.value) <= Int(aget) <= Int(searchAgeTo.value)))
{
}
}
}
})
`
I don't know how to filter results from dataSnapshot, I always get an errors. Here, I perform my searching, in ????? I don't know how search for selected value from pickerView:
if (self.sexG == sext as! String && Int(searchAgeFrom.value) <= Int(aget) <= Int(searchAgeTo.value)) && ?????)
{
}
I believe you have erors in unwrapping of snapshot.
Try this:
let dict = snap.value as! [String: AnyObject]
let latt = dict["lat"] as! Double
let lngt = dict["lng"] as! Double
// etc..
Hope it helps
First of all your if condition is not correct as of with searchAgeTo.value you are not comparing with any value also instead of casting snap.value to AnyObject cast it to proper dictionary in your case it is [String:Any].
Now to get the pickerView selected value you can use instance method selectedRow(inComponent:) or also use UIPickerViewDelegate method didSelectRow.
let selectedIndex = yourPickerView.selectedRow(inComponent: 0)
let selectedValue = yourPikcerArray[selectedIndex]
Now compare this in if condition this way.
for child in (snapshot.children) {
let snap = child as! DataSnapshot
let dict = snap.value as! [String:Any]
let latt = dict["lat"]
let lngt = dict["lng"]
let sext = dict["sex"] as! String
let statust = dict["status"] as! String
let aget = dict["age"]
if self.searchSex.selectedSegmentIndex == 0 {
self.sexG = "Male"
}
else {
self.sexG = "Female"
}
let selectedIndex = yourPickerView.selectedRow(inComponent: 0)
let selectedValue = yourPikcerArray[selectedIndex]
if (self.sexG == sext && Int(searchAgeFrom.value) >= Int(aget) && Int(aget) <= Int(searchAgeTo.value) && selectedValue == statust) {
//Handle here
}
}
But instead of filtering Firebase data this way better way is you can store all the data in some main array and than filter that main array according to your filter so that you will not need to observe Firebase data every time when you change your filter value. Also make one custom class or struct to manage all your Firebase data with array of that custom object.
I am facing error on 7th line it's giving "Cannot convert value of type'NSDictionary.Iterator.Element' (aka '(key: Any, value: Any)') to expected argument type 'NSDictionary'".
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
ref = snapshot.ref
let snapshotValue = snapshot.value as! [String: AnyObject]
if (snapshotValue["visitor"] != nil) {
for item in snapshotValue["visitor"] as! NSDictionary {
visitor = UserVisitor.init(visitorData: item)
}
}
snapshotValue["visitor"] is obviously an array so cast it to Swift Array containing dictionaries:
if let visitors = snapshotValue["visitor"] as? [[String:Any]] {
for item in visitors {
visitor = UserVisitor(visitorData: item)
}
}
Try a pure Swift approach like this :
// snapshotValue is a dictionary
if let snapshotValue = snapshot.value as? [String:Any] {
// The content of the "visitor" key is a dictionary of dictionaries
if let visitorDictionary = snapshotValue["visitor"] as? [String:[String:Any]] {
for (visitorId, visitorData) in visitorDictionary {
// This assumes that your initializer for UserVisitor is
// init(visitorData: [String:Any]) { ... }
visitor = UserVisitor.init(visitorData: visitorData)
}
}
}
Try not using NSDictionary or NSArray unless you really need to. Native Swift types work better in Swift...
You can write the else statements to handle data that is not in the expected format.
I currently use this pattern
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
let valid: Int? = 1
let status: String? = "ok"
if let v = jsonResult["valid"] as? Int, s = jsonResult["status"] as? String {
if v == valid && s == status{
//Do something
}
}
}
Is this the optimal method to check that v == 1 and s == "ok"
Or is it possible to do something like this answer, would it be better ?
Answer(Unwrapping multiple optionals in a single line)
if let v = jsonResult["valid"] as? Int, s = jsonResult["status"] as? String
where is(v, valid && s, status)
Any help is appreciated, thank you.
If you don't need v and s inside of the body of the if, you can just do the comparison directly:
if jsonResult["valid"] as? Int == 1 && jsonResult["status"] as? String == "ok" {
// Do something
}
Try:
if let v = jsonResult["valid"] as? Int, s = jsonResult["status"] as? String where (v == valid && s == status) {}
You should try guard statement
something like this
let dict = NSDictionary()
dict.setValue(Int(1), forKey: "one")
dict.setValue("String", forKey: "two")
guard let one = dict["one"] as? Int, two = dict["two"] as? String where one == 1 && two == "String" else {
print ("no")
return
}
print ("one is \(one) two is \(two)")
I have an application that is using the Foursquare API to download JSON data. I am using NSURLSession and the dataTaskWithRequest with completion block method to fetch the data. I am getting the data fine but sometimes a nested array named groups can be empty. And when I am parsing through the JSON like below, for some reason my conditional statement is not handling the empty array like I am expecting it should. Instead of evaluating the array as empty and proceeding to the "else" portion of the if let...else statement if instead throughs a runtime error stating: index 0 beyond bounds of empty array
if let response: NSDictionary = data["response"] as? [String: AnyObject],
groups: NSArray = response["groups"] as? NSArray,
// Error here \|/ (sometimes groups array is empty)
dic: NSDictionary = groups[0] as? NSDictionary,
items: NSArray = dic["items"] as! NSArray {
}
else {
// Never gets here. Why?
// IF the groups array is empty, then the if let should return
// false and drop down to the else block, right?
}
I am relatively new to Swift, can someone tell me why this is happening and what I can do to fix this? Thanks
You have to check explicitly outside an if letstatement if the array is empty, because
An empty array is never an optional
if let response = data["response"] as? [String: AnyObject], groups = response["groups"] as? NSArray {
if !groups.isEmpty {
if let dic = groups[0] as? NSDictionary {
items = dic["items"] as! NSArray
// do something with items
println(items)
}
}
} else ...
You can omit all type annotations while downcasting a type
However, you can perform the check with a where clause, this works in Swift 1.2 and 2
if let response = data["response"] as? [String: AnyObject],
groups = response["groups"] as? [AnyObject] where !groups.isEmpty,
let dic = groups[0] as? NSDictionary,
items = dic["items"] as? NSArray {
// do something with items
println(items)
} else {...
Use && operator between statments.
For example this won't crash:
var a = 4;
var c = 5;
var array = Array<Int>();
if a > 2 && c > 10 && array[0] != 0 {
}
Make sure the array is not empty before trying to access it:
if let response: NSDictionary = data["response"] as? [String: AnyObject],
let groups: NSArray = response["groups"] as? NSArray where groups.count > 0 {
if let dic: NSDictionary = groups[0] as? NSDictionary,
let items: NSArray = dic["items"] as? NSArray {
// Do something..
return // When the 2nd if fails, we never hit the else clause
}
}
// Do logic for else here
...