Access data in Dictionary from NSCountedSet objects - swift

I have an NSCountedSet consisting of String objects, if I iterate over the set and print it out, I see something like this:
for item in countedSet {
print(item)
}
Optional(One)
Optional(Two)
The countedSet is created from an Array of String objects:
let countedSet = NSCountedSet(array: countedArray)
If I print the array I see something like this:
["Optional(One)", "Optional(One)", "Optional(One)", "Optional(Two)", "Optional(Two)"]
Now, I want to use those counted strings to access data in a Dictionary, where the keys are String type and the values have the type [String : AnyObject]. If I print the dictionary, I see all the data.
However, if I use of the objects from the countedSet to access the dictionary, I always get a nil value back:
for item in countedSet {
let key = item as? String
let data = dictionary[key!] // Xcode forced me to unwrap key
print(data)
}
nil
nil
But
let key = "One"
let data = dictionary[key]
gives me the expected data.
What am I missing here, how can I access my data from the countedSet objects?
UPDATE: solved thanks to the comment from Martin R. The String objects were originally NSString objects (obtained from NSScanner), and I was casting them wrongly:
let string = String(originalString)
after I changed it to:
let string = (originalString as! String)
All works fine.

Related

Filter An Array Of Arrays By A Value In Firestore Swift

I'm looking to filter an array of arrays by specific value of one of the keys located within each array. Each nested array is read in from Firestore.
As an object, each nested array would look like this:
struct Video {
var url: String
var submissionDate: Timestamp
var submittingUser: String
}
I'm reading it in like this:
videos = document.get("videos") as? [[String : Any]] ?? nil
So far so good, but when I filter it like this:
filteredVideos = videos.filter { $0[2].contains(self.userIdentification) }
I can't do it without getting the error "Reference to member 'contains' cannot be resolved without a contextual type," an error which I was unable to find any relevant information on SO about.
I have read that some people say "Don't use arrays in Firestore!" but this is a build requirement.
Anyone have any ideas? Basically just need all arrays within the array where userId == submittingUser.
Reference Article:
I tried the answer from here: How to filter out a Array of Array's but no luck for this situation.
It's actually an array of dictionaries, not an array of arrays. All you need to do is construct the right predicate for the filter.
This is basically what your Firestore data looks like:
let videos: [[String: Any]] = [
["url": "http://www...", "submittingUser": "user1"],
["url": "http://www...", "submittingUser": "user2"]
]
This is the user you're looking for:
let userIdentification = "user2"
This is the predicate for the filer:
let filteredVideos = videos.filter { (video) -> Bool in
if let submittingUser = video["submittingUser"] as? String,
submittingUser == userIdentification {
return true
} else {
return false
}
}
You can shorthand this down to a single line if you're okay with force-unwrapping the dictionary (if you're 100% certain every video will have a valid submittingUser value):
let filteredVideos = videos.filter({ $0["submittingUser"] as! String == userIdentification })

Getting Array value in a dictionary swift

I am trying to get key and value in a Dictionary while I am able to the key and map it to a dictionary, I am unable to get the value which is an array.
var dict = [String: [String]]
I was able to get the key as an array which is what I want like:
var keyArray = self.dict.map { $0.key }
How can I get the value which is already an array
Use flatMap if you want to flatten the result you get when you use map which is of type [[String]].
let valueArray = dict.flatMap { $0.value } // gives `[String]` mapping all the values
Here is how you get each string count Array
var dict = [String: [String]]()
let countOfEachString = dict.map { $0.value }.map{ $0.count }
Each value is a string array .. so to access each array you need to use map again

Swift 3: Dict from only one object in struct in array

I have a struct that looks like:
struct nameStruct {
let name: String
let index: Int
}
I have an NSMutableArray that contains about 50 objects of this struct
Right now, I fill the contents of my namesDict with
let namesDict:[String: Any] = ["names" : namesArray]
However, because I only need the index object for sorting, I'd like to only add the name attribute to the dictionary, something like this:
let namesDict:[String: Any] = ["names" : namesArray.name]
or, because of swift's nature:
let namesDict:[String: Any] = ["names" : (namesArray as! [nameStruct]).name]
(focus on the .name part which obviously doesn't work in Swift)
Right now, my best guess would be to create a new array in a loop, only adding the name of the contents of my namesArray - but if there was a way to do this in one line without another array "in between", this would be really nice.
You can use map.
let namesDict: [String: Any] = ["names": namesArray.map({ ($0 as! nameStruct).name })]

Unable to convert anyObject to String

I am trying to run the following code, but am unable to convert the rest.value without the preceeding "Optional". The following is the code I get when attempting to solve the issue:
//for Withdrawl children
transRef.child("Withdraw").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
//creates enumerator of the snapshot children for
let enumerator = snapshot.children
while let rest = enumerator.nextObject() as? FIRDataSnapshot {
let curString = (rest.value) as! String
self.anArray.append(curString)
//printing the rest.value to make sure there are children to iterate through
print(rest.value)
}
self.tableView.reloadData() //<<<<<<<<<<<< RELOAD TABLEVIEW
})
this is the error I am receiving: Could not cast value of type '__NSCFNumber' (0x10d068368) to 'NSString'
According to the Firebase documentation the value property: "Returns the contents of this data snapshot as native types. Data types returned: + NSDictionary + NSArray + NSNumber (also includes booleans) + NSString".
The var returns an Any? in order to handle this versatility.
In this case it looks like it is returning an NSNumber, so the String cast fails. I'm not sure exactly the context of the value in this scenario, but if you are sure that it is going to return a number every time you could cast it to a numerical type (Swift/Objective-C bridging allows NSNumber to be casted to any of the primitive number types in Swift), and then pass it into a String initializer to get a String out of it. e.g.:
let curNumber = rest.value as! Double
let curString = String(curNumber)
If you aren't sure what type will be returned, but are expecting to put it into an Array of Strings then you should probably check before you cast e.g.:
if let curNumber = rest.value as? Double {
let curString = String(curNumber)
self.anArray.append(curString)
}
Instead of (rest.value) as! String, say [Swift 2] String(rest.value) or [Swift 3] String(describing:rest.value). [If rest.value is an Optional, then say rest.value! in those formulations.]

Saving more than one value to a Dictionary key in a loop with an Array

I have this block of code
//start of the loop
if let objects = objects as? [PFObject] {
for object in objects {
//saving the object
self.likerNames.setObject(object["fromUserName"]!, forKey: saveStatusId!)
}
}
likerNames is an NSMutableArray declared earlier, saveStatusId is a string I also declared and saved earlier (It's just an objectId as a String), and object["fromUserName"] is an object returned from my query (not shown above).
Everything is working fine as it is but my query sometimes returns more than one object["fromUserName"] to the same key which is saveStatusId. When this happens the value I have for that saveStatusId is replaced when I actually want it to be added to the key.
So want it to kind of look like this
("jKd98jDF" : {"Joe", "John"})
("ksd6fsFs" : {"Sarah"})
("payqw324" : {"Chris", "Sarah", "John"})
I know you can use Arrays but I'm not sure how I would go about that to get it to work in my current situation.
So my question would be how to I get my key (saveStatusId) to store more than one value of object["fromUserName"]?
Something like this could work
let key = saveStatusId!
let oldValue = self.likerNames.objectForKey( key ) as? [String]
let newValue = (oldValue ?? []) + [ object["fromUserName" ] ]
self.likerNames.setObject( newValue, forKey: key )
If likerNames has an array in slot[saveStatusId], append the new value, otherwise create an array and put that in the right slot