Delete Objects From Parse/ Cannot cast to PFObject/ NSArrayM - ios

My problem is:
I am querying user["key"] that I am attempting to assign to a new variable, as on the documentation.
The column in Parse is an array of Strings, in my query, if I println(user["key"]) it returns the correct objects.
However, when I do:
let myVariable = user["key"] as String
or
let myVariable = user["key"] as! String
I have the error:
Could not cast a value of type _NSArrayM to NSString
My end goal is to retrieve objects from Parse, and submit an "if" condition and then delete the results. For this I need to convert the objects into PFObject and this is where I struggle.
To add, I can only downcast to AnyObject! from let myVariable = user["key"]
and when I try to delete this object, I have the error
NSArrayM delete: unrecognised selector sent to instance.
Any help would be greatly appreciated.

Parse.com normally return an array, as you can see in your error message:
Could not cast a value of type _NSArrayM to NSString
__NSArrayM is a code-word for a mutable array, so you are trying to cast an array to a string.
If you are sure your query is return just one result you can retrieve just the last (and only) element in the array and cast to string.
if let myVariable = user["key"].last as? String{
println("myVariable key is \(myVariable)"
} else {
println("Could not retrieve key")
}

Related

Error while assigning value from nested NSDictionary to a variable?

I have a dictionary assigned to a variable restaurant from this API.
API Call
I am trying to assign.
let restaurantLat = restaurants[indexPath.row]["geometry"]!["location"]!!["lat"] as? String
This is showing an error:
type any has subscript members.
Access json output data as below:
let restaurantLat = restaurants["results"][indexPath.row]["geometry"]!["location"]!!["lat"] as? String
Because results key contain list of array.

can't get number from NSArrayM

i get the below error when trying to retrieve a key name from a query. and then cast it as an int of use by viewcontroller.
Could not cast value of type '__NSArrayM' (0x1073ebdb0) to 'NSNumber' (0x1069f3488).
this is the line in the query:
tempVarLDS = object.value(forKey: keyName)
when printed this returns
(
7
)
so it is an array. but i can't seem to access it via
tempvarLDS[0]
or any of the usual suspects. any idea how to get this int?
If it's an NSArray of NSNumbers, you should be able to cast it as an array of integers.
// Cast it
let tempvarLDS:[Int] = object.value(forKey: keyName) as! [Int]
// Loop
for num in tempvarLDS {
print(num)
}
I don't see why that wouldn't work

iOS Swift Updating Dictionary In An Array

I have an array of dictionaries inside a dictionary. I initialize it like this:
var fillups:[NSMutableDictionary] = []
Then I load it like this:
fillups = userDefaults.object(forKey: car) as! NSArray as! [NSMutableDictionary]
Then when I try to update a dictionary element in the array I get the "mutating method sent to immutable object" error. Here's my code to update the record:
let dict=fillups[row]
dict.setValue(odometerField.text, forKey: "odometer")
dict.setValue(gallonsField.text, forKey: "gallons")
fillups[row]=dict
The error occurs in my first setValue line.
Objects that you retrieve from NSUserDefaults are immutable even if they were mutable when they were inserted. You need to take the immutable objects you get from defaults and create mutable versions of them. You also shouldn't force unwrap everywhere if you don't want your app to crash.
if let array = userDefaults.object(forKey: car) as? [NSDictionary] {
fillups = array.map { ($0.mutableCopy() as! NSMutableDictionary) }
}
You also don't need the fillips[row] = dict line since NSMutableDictionary is a reference type and editing the reference you pull out of the array is already editing the one inside the array.
If you want to mutate your dict, you need to declare it with 'var' not with 'let'; 'let' is for constants. Also fix the unwrapping problems pointed out by the comment
let dict=fillups[row]
should be
var dict=fillups[row]

Ambiguous use of subscript?

I can make a Facebook SDK Graph Request to get a user's likes, but I'm having trouble taking the returned values and storing one of the keys in an array of Strings. The request returns an NSDictionary of keys/values. Then, using objectForKey I can get the data key which returns what I want: the id and name of the "liked" page on Facebook.
Data returns elements like this:
{
id = 486379781543416;
name = "Star Wars Movies";
},
I specifically want only the "name" of all of these objects and to throw them into an array [String]. I tried to loop through the objects but I'm getting error ambiguous use of subscript. Here's the relevant code:
request.startWithCompletionHandler{(connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
let resultdict = result as! NSDictionary
let likes = resultdict.objectForKey("data") as! NSArray
print("Found \(likes.count) likes")
print(likes)
for object in likes{
let name = object["name"] as! String //error: ambiguous use of subsript
print(name)
}
}
After doing some research it looks like the issue is with the NSArray and that I should instead use Swift data types. I tried casting it to a Swift array but I got different errors.
What's the best way to handle this error?
Thanks!
update: Here is what the facebook API request returns:
{
data = (
{
id = 111276025563005;
name = "Star Wars (film)";
},
{
id = 115061321839188;
name = "Return of the Jedi";
}
);
paging = {
cursors = {
after = MTE1MDYxMzIxODM5MTg4;
before = Mjc0NzYzODk2MTg4NjY5;
};
next = "https://graph.facebook.com/v2.5/10155262562690368/likes?access_token=<redacted>";
};
}
You should always use the native Swift collection types wherever possible as NSArray and NSDictionary are really type-inspecific, and therefore can easily trigger "ambiguous use of subscript" errors.
You'll also want to avoid force down-casting, in case you receive data that's in the wrong format, or no data at all. This situation would be more elegantly handled with a guard, in order to prevent a crash. If your program depends on the force down-casting succeeding, and therefore should crash – then you can always call fatalError in the guard, with a descriptive error message in order to assist you in debugging the problem.
If I understand your data structure correctly, the request returns an AnyObject that should be a [String:AnyObject] (A dictionary of strings to any objects). In the case of the "data" key, the AnyObject value is then a [[String:AnyObject]] (An array of dictionaries of strings to any objects).
Therefore you'll want to do your casting in two stages. First, using a conditional downcast on your result to cast it as a [String:AnyObject]. If this fails, then the else clause of the guard will be executed and the code will return. You'll then want to get out your "data" value (your 'likes' array), and conditionally downcast it to a [[String:AnyObject]]. Both of these statements will handle the possibility of resultDict or resultDict["data"] being nil.
guard let resultDict = result as? [String:AnyObject] else {return}
guard let likes = resultDict["data"] as? [[String:AnyObject]] else {return}
You can put whatever error handling logic you want in the brackets of these statements to handle cases in which the results dictionary doesn't exist, was the wrong format, or there wasn't a 'likes' array in it.
You can then get an array of 'like' names through using flatMap.
let likeNames = likes.flatMap{$0["name"] as? String}
This will create an array of the like names of each dictionary – if the like names don't exist or aren't strings, then they won't be added. Because the compiler knows for certain that likes is a [[String:AnyObject]] – there's no ambiguity in subscripting its elements.
If you want a more general approach such as you're doing in your question, you can use a guard statement within a for loop.
for object in likes {
guard let name = object["name"] as? String else {continue}
print(name)
}
Again, you can put whatever error handling you wish in the brackets of the guard.

How to create and access a NSDictionary in Swift

I am busy converting to Swift and am trying to figure out how to do the following in Swift
NSArray arrayOfStrings1 = {#"Substring1", #"Substring2", nil};
Dictionary dict = {#"MainString1", arrayOfStrings1};
So in Swift I have the following:
var dictionary = [String: Array<String>]() // is this correct ??
var array: [String] = ["Substring1", "Substring2"]
dictionary["MainString1"] = ["Substring1.1", "Substring1.2"]
dictionary["MainString2"] = ["Substring2.1", "Substring2.2"]
Now in order to access the array I use
let array = dictionary["MainString1"]
let item0 = array[0]
but this fails with a compiler error which seems to indicate that array is in fact a String not an array of strings.
What am I missing here?
The issue is actually that a subscript lookup for a Dictionary in Swift returns an optional value:
This is a pretty great feature - you can't be guaranteed that the key you're looking for necessarily corresponds to a value. So Swift makes sure you know that you might not get a value from your lookup.
This differs a little bit from subscript behavior for an Array, which will always return a value. This is a semantically-driven decision - it's common in languages for dictionary lookups to return null if there is no key - but if you try to access an array index that does not exist (because it's out of bounds), an exception will be thrown. This is how Swift guarantees you'll get a value back from an array subscript: Either you'll get one, or you'll have to catch an exception. Dictionaries are a little more lenient - they're "used to" not having the value you're asking for.
As a result, you can use optional binding to only use the item if it actually has a value, like so:
if let theArray = dictionary["MainString1"] {
let item0 = theArray[0]
} else {
NSLog("There was no value for key 'MainString1'")
}

Resources