Reputation: 13
I have been working with an array of dictionaries in Swift (version 7 beta 4) using NSDictionary. The array is a collection of fmdb results which contain differing data types. I would like to end up with an array of native swift dictionaries in order to use the filter functionality of swift collection types. The following is a snippet of the query function I'm using the create the array:
class func query(sql:String) -> [NSDictionary] {
let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask, true)
let docsDir = dirPaths[0] as String
let databasePath:String = docsDir.stringByAppendingPathComponent("myDB.db")
let db = FMDatabase(path: databasePath as String)
var resultsArray:[NSDictionary] = []
if db.open() {
let results:FMResultSet? = db.executeQuery(sql, withArgumentsInArray: nil)
while (results?.next() == true) {
resultsArray.append(results!.resultDictionary()) //appending query result
}
db.close()
} else {
print("Error: \(db.lastErrorMessage())")
}
return resultsArray
}
I tried using AnyObject such as:
class func query(sql:String) -> [[String:AnyObject]] {
let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask, true)
let docsDir = dirPaths[0] as String
let databasePath:String = docsDir.stringByAppendingPathComponent("Kerbal.db")
let db = FMDatabase(path: databasePath as String)
var resultsArray:[[String:AnyObject]] = []
if db.open() {
let results:FMResultSet? = db.executeQuery(sql, withArgumentsInArray: nil)
while (results?.next() == true) {
resultsArray.append(results!.resultDictionary() as! Dictionary<String,AnyObject>)
}
db.close()
} else {
print("Error: \(db.lastErrorMessage())")
}
return resultsArray
}
however I can't use the filter such as resultsArray.filter({$0["fieldName"] == "part"})
with AnyObject
.
My question: Is it possible to create this array with native Swift dictionaries even though the dictionaries have different types? Could the new protocol extension be used on collection type to solve this problem?
Any suggestions are appreciated.
Upvotes: 1
Views: 5612
Reputation: 13263
If you don't know which objects you are dealing with you have to use filter like so:
resultsArray.filter{ ($0["fieldName"] as? String) == "part"}
So you optionally cast the value to the desired type and compare it.
Note: I'm using the trailing closure syntax.
As suggestion I would use a tuple of different arrays which hold dictionaries:
// some dummy values
let resultsArray: [[String : AnyObject]] = [["Hi" : 3], ["Oh" : "String"]]
var result = (doubles: [[String : Double]](), strings: [[String : String]]())
// going through all dictionaries of type [String : AnyObject]
for dict in resultsArray {
// using switch and pattern matching to cast them (extensible for more types)
// you have to up cast the dictioanary in order to use patten matching
switch dict as AnyObject {
case let d as [String : Double]: result.doubles.append(d)
case let s as [String : String]: result.strings.append(s)
default: fatalError("unexpected type")
}
}
return result
Upvotes: 2
Reputation: 4958
You should probably adopt the Equatable protocol, not all AnyObjects are such in fact, and so no comparison and thereafter filtering may be done.
Upvotes: 0