I'm working with the parse framework for an App that I'm converting to Xcode 7. One of the interesting errors which has occurred as part of migrating the project is the following:
Cast from 'MDLMaterialProperty?!' to unrelated type 'PFUser' always fails
The offending line seems to be the "if let" clause below. I've commented the old line which worked fine in the previous version of Swift for comparison.
With respect to what this is actually doing - I've passed an array of Parse objects into "likesForThankful" where a pointer "userID" refers to a related PFUser. As part of this method I'm writing individual PFUsers to an array.
Any help is appreciated - thanks in advance.
//Add PFUsers who Like Post to our FeedItem
private func callbackFromLikesProcessing(likesForThankful:[AnyObject], againstFeedItem:FeedItem){
//Instantiate our Objective C compatible array for processing later
againstFeedItem.parseUsersObjectsWhoLikePost = NSMutableArray()
//Loop through likes and add PFUsers to array of users who like post
for usersWhoLikePost in likesForThankful{
// if let parseUserWhoLikesPost = usersWhoLikePost["userID"] as PFUser{
if let parseUserWhoLikesPost = usersWhoLikePost["userID"] as? PFUser {
againstFeedItem.parseUsersObjectsWhoLikePost.addObject(parseUserWhoLikesPost)
}
}
Andrew
Figured this out if it can help anyone - it's basic Swift Syntax (though I'm not sure why the compiler let me get away with this in the first version of Swift!).
Because usersWhoLikePost is a PFObject which happens to contain a pointer to a PFUser object I needed to conditionally unwrap this first like so:
for usersWhoLikePost in likesForThankful{
if let parseLikeObject = usersWhoLikePost as? PFObject{
if let parseUserWhoLikesPost = parseLikeObject["userID"] as? PFUser {
againstFeedItem.parseUsersObjectsWhoLikePost.addObject(parseUserWhoLikesPost)
}
}
}
After this I could continue as I had previously done and access the "userID" property with a conditional unwrap of the PFUser object.
Related
From a server I receive a JSON string, then I try to convert it to an NSDictionary this way:
let JSON = try NSJSONSerialization.JSONObjectWithData(rToData!, options:[])
guard let JSONDictionary:NSDictionary = (JSON as! NSDictionary) else {
print("My grandma is way more NSDictionary than this")
return
}
Once converted, I try to get some data contained in the dictionary: in particular I need an array I can access this way:
let myArray = JSONDictionary["data1"][0]["data2"];
XCode really doesn't like this idea, it puts an arrow under the first bracket and says Value of optional type "AnyObject?" not unwrapped, did you mean to use "!" or "?" ?. I follow its suggestion and I insert a "!", converting my preceding code to this:
let myArray = JSONDictionary["data1"]![0]["data2"];
At this point, the following line (where I count the number of elements in data2) shows an error, stating AnyObject has no member count.
The only thing that seems to work fine is this solution but, apart from being ugly and unreadable, I really don't understand it:
let myArray = (JSONDictionary["data1"]?[0]["data2"])!;
Can you help me understand why this basic access to a key in a dictionary must be so intricate?
I must say I like Swift but I spend a lot of time dealing with optionals and bizarre XCode alerts.
There is no guarantee that your JSON dictionary will contain a value for the key data1 (OK, you know it will, but Swift doesn't) so JSONDictionary["data1"] returns an optional. You need to unwrap the optional with ? or !
Also, since you have an NSDictionary, not a Swift dictionary, Swift doesn't know the type of the values, so they are AnyObject. Now again, you know it is an array, but Swift doesn't so you get an error stating that AnyObject doesn't have a count method.
While it is more verbose, it is cleaer for both the compiler and anyone else looking at your code if you split the line into multiple lines. It also lets you downcast the various objects so that Swift knows what is going on and handle any malformed JSON;
if let array1 = JSONDictionary["data1"] as? NSArray {
if let dictionary1 = array1[0] as? NSDictionary {
if let data2Array = dictionary1["data2"] as? NSArray {
let count=data2Array.count
}
}
}
You could implement appropriate else statements to handle errors
Optionals are one of Swift's most powerful features. They help avoid a whole family of bugs associated with uninitialised variables and special sentinnel values for boundary conditions. It is important that you learn how they can help you and not just throw ? or ! at your code until it compiles.
I am trying to get an array from a Parse.com database in my Swift app. For some reason, the array returned is always nil. I checked the permissions to make sure that the data can be accessed by my app, I find it really hard to find a starting point for this bug.
Here's my code:
let username = PFUser.currentUser()?.objectId
print("username: \(username)")
let bannedUsers = PFUser.currentUser()!["bannedUsers"] as? NSArray
print("bannedUsers: \(bannedUsers)")
The log output:
username: Optional("Nmmtb07PoR")
bannedUsers: nil
A screenshot from the database to show the array is not nil:
The exact value of the array:
[{"__type":"Pointer","className":"_User","objectId":"mG33sM3fcC"}]
I tried playing around with the contents of the array, but no matter what I put in it, whether it's a pointer or just a string, I always get 'nil'. I hope you can help.
Solved:
I added the line
PFUser.currentUser()?.fetch()
This refreshed the user and I got the proper data instead of 'nil'. Hope it helps if you have a similar issue in the future.
How about:
let bannedUsers = PFUser.currentUser()!.bannedUsers as? NSArray
Try using: PFUser.currentUser()!.objectForKey("bannedUsers")
or PFUser.currentUser()!.valueForKey("bannedUsers")
Your column could be not included in the currentUser object so you would have to query users and include the bannedUsers column.
You can do it by the following:
let query = PFUser.query()
query?.includeKey("bannedUsers")
do {
let user = try query?.getObjectWithId((PFUser.currentUser()?.objectId)!)
let bannedUsers = user?.valueForKey("bannedUsers")
print(bannedUsers)
} catch {
print(error)
}
I'm building my first iOS app using Swift 2.0 and I'm running in to the following error:
Cast from 'Ride' to unrelated type 'NSDictionary' always fails
at this line:
if let rowData: NSDictionary = ride as? NSDictionary,
Just below my class declaration I'm declaring rides like this:
var rides = [Ride]()
And above the error line I have added this:
let ride = self.rides[indexPath.row]
Screenshot:
And my Ride class:
Can someone tell me what I'm doing wrong and how to fix this?
struct Ride is not a subtype of NSDictionary. They are completely different concept.
Therefore, the casting if let rowData: NSDictionary = ride as? NSDictionary always fails.
Since rides's type is [Ride], let ride = rides[indexPath.row]'s type is Ride.
No optional unwrapping is required. Use the properties(name, state, ...) directly.
So, I think the code should be something like this.
let ride = rides[indexPath.row]
dataFull = ride.name
dataState = ride.state
dataUrlString = ride.image
...
just cast to the proper type : Ride
if let rowData = ride as? Ride,
but as the datasource is defined as Ride anyway this check is not needed at all
Edit:
The properties of Ride are all declared as non optional types, so you never have to check for nil. That's a huge benefit of the Swift language
After updating the xcode and my device some functions are not running anymore.
see It:
var jsonUnico: NSMutableArray! = jsonResult["lista"] as? NSMutableArray
self.tableList.addObjectsFromArray(jsonUnico)
Error: Cannot invoke 'addObjectsFromArray' with an argument list of type '(NSMutableArray!)'
It was working yesterday before upgrading
note: the tablelist is an NSMutableArray
Swift 1.2 no longer implicitly converts between NSArray and Swift’s native array type – you need to explicitly cast from one to the other. Since addObjectsFromArray takes a Swift array, that means you need to convert it to [AnyObject].
Normally you’d get a more helpful error message: error: 'NSMutableArray' is not implicitly convertible to '[AnyObject]'; did you mean to use 'as' to explicitly convert?, with a offer to “fix-it”. But it looks like this isn’t happening because of your use of implicitly-unwrapped optional NSMutableArray!.
But… this isn’t such a bad thing, since using implicitly-unwrapped optionals like that when fetching values out of dictionaries is dangerous (if the entry is ever not there, your app will crash). An alternative is:
if let jsonUnico = jsonResult["lista"] as? NSMutableArray {
let tableList = NSMutableArray()
// Xcode will recommend adding the "as [AnyObject]"
tableList.addObjectsFromArray(jsonUnico as [AnyObject])
}
But since you’re already doing an as above it, you may as well combine them:
if let jsonUnico = jsonResult["lista"] as? [AnyObject] {
tableList.addObjectsFromArray(jsonUnico)
}
I had some troubles last night accessing the elements of an array created via the componentsSeparatedByStringMethod. My goal is to extract some information from an url content variable.
var arr = urlContent.componentsSeparatedByString("<span class=\"Some HTML class\">")
I printed arr to the log, it works perfectly
I'd like to access the second element of the array arr, in order to get the info I need (the information right after the span tag). I thought:
var info = arr[1]
would work, but it doesn't. I get an error message saying that the subscript method doesn't work for an object of type "AnyObject" or something similar. So the problem is arr is not an Array Object type but an AnyObject type. I tried to convert it to an array but it didn't work either.
Could anybody help through this little trouble? :)
In xcode 6.1.1 componentsSeperatedByString method returns [AnyObject]. You have to cast it to [String] like so:
if let arr = urlContent.componentsSeparatedByString("<span class=\"Some HTML class\">") as? [String] {
// arr is now [Sstring]
}
In xcode 6.3 beta this method returns [String] so cast is not needed.