Then i try to convert a key from PFObject to a String it gives me a error. I can't find anything on Parses website. Please help
var findProgram = PFQuery(className: "Programs")
findProgram.getObjectInBackgroundWithId(data["program"] as! String!, block: { (object: PFObject?, error) -> Void in
if error == nil {
var objects = object["name"] as! String
print(objects)
self.programUpdated.append(object?.createdAt as NSDate!)
}
})
I think this is what you're going to have to do, try this:
//explicitly giving the objects var a type of String
var objects:String = object["name"] as! String
You shouldn't get an error after that.
Good luck!
I think this will be the batter way to do that:
if let objects = object?.objectForKey("name") as? String{
print(objects)
self.programUpdated.append(objects?.createdAt as NSDate!)
}
Related
I'm currently pulling data via Twitter's Search API.
Once I receive the data, I am trying to parse and save the data to my TweetDetails class (which is to hold the author's name, the url of their profile pic, the text of the tweet, the location of the tweet, the tweet id and user id).
In some cases, the Tweets do not have a location (I think it has something to do if they're retweeted), and the certain dictionary (here being tweetsDict["place"]) that would otherwise hold that information, instead returns NSNull.
On those occasions, I receive this error
Could not cast value of type 'NSNull' (0x1093a1600) to 'NSDictionary' (0x1093a0fe8).
Here is my code as I am trying to parse the data and save it to objects in my TweetDetails class
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: \(connectionError)")
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
if let tweets = json["statuses"] as? [NSDictionary] {
for tweetsDict in tweets {
let text = tweetsDict["text"] as! String
let tweetID = tweetsDict["id_str"] as! String
let place = tweetsDict["place"] as! NSDictionary
// this line ^^ is where the error occurs
let city = place.valueForKey("full_name")
let user = tweetsDict["user"] as! NSDictionary
let userID = user.valueForKey("id_str")
let screenName = user.valueForKey("screen_name")!
let avatarImage = user.valueForKey("profile_image_url_https")!
let tweet = TweetDetails(authors: screenName as! String, profileImages: avatarImage as! String, tweetTexts: text, tweetLocations: city as! String , tweetIDs: tweetID , userIDs: userID as! String)
self.allTweets.append(tweet)
self.tweetTableView.reloadData()
}
}
} catch let jsonError as NSError {
print("json error: \(jsonError.localizedDescription)")
}
}
I have tried to create some 'if-let' statements to provide alternatives for these occasions, but nothing has worked.
Could someone please help me to create a custom alternative around when certain JSON data returns as NSNull. (Even something as simple as turning my "city" variable into the string "Unknown Location" in the cases when the data returns NSNull).
Thanks in advance and please let me know if there is anything else I can add to provide more clarity to this question.
As others have pointed out, you can use optional binding (if let), or, in this case, even easier, just employ optional chaining:
let city = tweetsDict["place"]?["full_name"] as? String
This way, city is an optional, i.e. if no value was found because there was no place or full_name entry, it will be nil.
It would appear, though, that your TweetDetails is force casting city to a String. Does it absolutely require a city? It would be best to change this method so that city was optional and gracefully handle nil values there. Alternatively, you can replace nil values for city to some other string, e.g. with the nil coalescing operator:
let city = tweetsDict["place"]?["full_name"] as? String ?? "Unknown city"
That returns the city if found, and "Unknown city" if not.
I see a lot of force data type casting in your code witch is very dangerous, especially when parsing JSON. The correct way of dealing with nullability is not to avoid it by trying to do the same thing we did in objective-c but to prepare to receive nil and react accordingly. Your data model should represent the fact that sometime a tweet have no location so some properties of TweetDetails should be marked as optionals.
The code exemple bellow is completely untested but give you an idea of what your code can look like dealing with nullability.
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: \(connectionError)")
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
if let tweets = json["statuses"] as? [[String: AnyObject]] {
for tweetsDict in tweets {
if let text = tweetsDict["text"] as? String,
tweetID = tweetsDict["id_str"] as? String {
var city: String?
if let place = tweetsDict["place"] as? [String: AnyObject] {
city = place.valueForKey("full_name")
}
var userID: String?
var screenName: String?
var avatarImage: String?
if let user = tweetsDict["user"] as? [String: AnyObject] {
userID = user["id_str"] as? String
screenName = user["screen_name"] as? String
avatarImage = user["profile_image_url_https"] as? String
}
let tweet = TweetDetails(authors: screenName, profileImages: avatarImage, tweetTexts: text, tweetLocations: city, tweetIDs: tweetID, userIDs: userID)
self.allTweets.append(tweet)
}
}
self.tweetTableView.reloadData()
}
} catch let jsonError as NSError {
print("json error: \(jsonError.localizedDescription)")
}
}
I am trying to build a chat application, but I have a problem with this code:
func loadData() {
let FindTimeLineData: PFQuery = PFQuery(className: "Message")
FindTimeLineData.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, NSError) -> Void in
self.MessagesArray = [String]()
for MessageObject in objects {
let messageText: String? = (MessageObject as! PFObject) ["Text"] as? String
if messageText != nil {
self.MessagesArray.append(messageText!)
}
}
}
}
I need to retrieve data from Parse, but the .findObjectsInBackgroundWithBlock method tells me that it cannot convert a value of type AnyObject into Void in. How can I resolve this problem? Thanks in advance.
Try it like this instead:
var query = PFQuery(className: "Message")
query.findObjectsInBackgroundWithBlock {
(remoteObjects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
print("Retrieved \(remoteObjects!.count) messages from server.")
self.MessagesArray = [String]() // By convention, you should name this "messagesArray" instead, and initialize it outside this method
for messageObject in remoteObjects {
if let messageText: String? = messageObject["Text"] as? String {
self.messagesArray.append(messageText)
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
(not properly proof-read, but you should be able to get it to work from this)
For the record, there are LOTS of duplicate questions with this problem - i know, as I had the same problem after converting Parse code to Swift 2.1.
So, please do a little more research before you post a question. Often, SO even hints at you similar questions as you are typing...
As for the answer, the Parse API doesn't force you to cast the object as AnyObject anymore in the completion block of a query, so it can look just like this:
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let messages = objects {
for message in messages {
.... etc
I am saving a parse query to a array but i ket the following error on if let objects = objects as? [PFObject]
And the following error happens Downcast from '[PFObject]?' to '[PFObject]' only unwraps optionals.
any one know how to solve this?
func getArray(funcstring: String){
var userGeoPoint: PFGeoPoint
PFGeoPoint.geoPointForCurrentLocationInBackground {
(geoPoint: PFGeoPoint?, error: NSError?) -> Void in
if error == nil {
userGeoPoint = geoPoint!
}
}
var searchQuery: [String] = [String]()
var query = PFQuery(className:"User")
query.whereKey("geoLocation", nearGeoPoint:userGeoPoint)
query.limit = 100
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects as? [PFObject] {
for object in objects {
self.searchQuery.append(object.objectForKey("objectId") as! String)
}
}
} else {
print("\(error?.userInfo)")
}
}
}
objects is declared as [PFObject]?.
You're going to downcast the object to something the compiler already knows.
Just check for nil
if let unwrappedObjects = objects {
for object in unwrappedObjects {
self.searchQuery.append(object.objectForKey("objectId") as! String)
}
}
or still "swiftier"
if let unwrappedObjects = objects {
self.searchQuery = unwrappedObjects.map{ $0["objectId"] as! String }
}
I'm developing a simple iOS application. It's a simple quiz app. I'm using Parse to store my questions, answers etc. I've read all the documentation and cannot find why this code to retrieve an object is not working.
var query = PFQuery(className: "Test_Questions")
query.getObjectInBackgroundWithId("cJzv2JdMej", block: {
(questionObject: PFObject?, error: NSError?) -> Void in
let thisQuestion = questionObject["question"] as! String
//Error here: AnyObject is not convertible to String
})
Your help would be much appreciated!
Console Output:
Optional(What statement must come before an else statement?)
You should try this instead:
var query = PFQuery(className: "Test_Questions")
query.getObjectInBackgroundWithId("cJzv2JdMej", block: {
(questionObject: PFObject?, error: NSError?) -> Void in
if error == nil {
println(questionObject)
//if there's info in the console you know the object was retrieved
let thisQuestion = questionObject["question"] as? String
} else {
println("Error occurred retrieving object")
}
})
If that doesn't work you can also try let thisQuestion = questionObject.valueForKey("question"). Also make sure that Parse is actually returning an object by adding a print statement such as println(questionObject) after it has been retrieved so that you know Parse is returning an object.
Got it!
var query = PFQuery(className: "Test_Questions")
query.getObjectInBackgroundWithId("cJzv2JdMej", block: {
(questionObject: PFObject?, error: NSError?) -> Void in
let thisQuestion: AnyObject! = questionObject!.valueForKey("question")
self.question.text = thisQuestion as? String
})
Hello I want to get some data from my parse.com class called "Tags" in this class there are two 3 cols "objectID", "username" and "tagtext". I want to read a record finding by ID and afterwords I want to save "useername" and "tagtext" into two strings. I have done it like it is in the parse.com documentation:
#IBAction func readAction(sender: UIButton) {
var query = PFQuery(className:"Tags")
query.getObjectInBackgroundWithId("IsRTwW1dHY") {
(gameScore: PFObject?, error: NSError?) -> Void in
if error == nil && gameScore != nil {
println(gameScore)
} else {
println(error)
}
}
let username = gameScore["username"] as! String
let tagtext = gameScore["tagtext"] as! String
println(username)
println(tagtext)
}
I get an error called fatal error: unexpectedly found nil while unwrapping an Optional value , please tell me what is wrong in my code.
My class:
The problem is that:
let username = gameScore["username"] as! String
let tagtext = gameScore["tagtext"] as! String
gameScore["username"] and gameScore["tagtext"] can return nil values, and when you say as! String you say that it will be a String, and it is nil.
Try something like:
let username = gameScore["username"] as? String
let tagtext = gameScore["tagtext"] as? String
your error is happening because of that, but your final code should look like this:
#IBAction func readAction(sender: UIButton) {
var query = PFQuery(className:"Tags")
query.getObjectInBackgroundWithId("f3AXazT9JO") {
(gameScore: PFObject?, error: NSError?) -> Void in
let username = gameScore["username"] as? String
let tagtext = gameScore["tagtext"] as? String
println(username)
println(tagtext)
if error == nil && gameScore != nil {
println(gameScore)
} else {
println(error)
}
}
}
Because the getObjectInBackgroundWithId is async.
You are trying to read from your response object gameScore but it is still nil because getObjectInBackgroundWithId is an asynchronous method meaning that it will return a result once it is finished. Put the two lines inside the handler and start from there.