Swift Parse.com unable to retrieve object - xcode

So I am trying to get a String that is saved within an object from Parse.com. Here is the code that I am using to do so:
var query: PFQuery = PFQuery(className: "Replys")
query.getObjectInBackgroundWithId("ipmdKB0N1N") {
(object: PFObject?, error: NSError?) -> Void in
if error == nil && object != nil {
println(object)
self.replyField.text = object["Replys"]
} else {
println(error)
}
}
I want to make this string the text of the label called "replyField" but when I try to do that, Xcode gives an error like "Cannot assign value "AnyObject?" to type "String?"" Even when I add as! String, it still gives a similar (though not exactly the same) error. Any ideas why?

You should unwrap optional of object. Such as object!["Replys"] or object?["Replys"]
Like below:
self.replyField.text = object!["Replys"] as! String
or
self.replyField.text = object?["Replys"] as! String

let replysString = object["Replys"] as! NSString
self.replyField.text = replysString as String

Related

Swift: Could not cast value of type 'Could not cast value of type '__NSCFString' (0x10e4d5ef0) to 'NSDictionary' (0x10e4d6bc0).'

I am trying to get post data in dictionary. Let first me show what I am doing.
manager.POST(url, parameters: dict,
success: { (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
if let jsonDict = self.parseJSON(responseObject) {
print(jsonDict)
// Error occur on the following line
let dataDict = jsonDict["data"] as! [String : AnyObject]
// Error Info: Swift: Could not cast value of type 'Could not cast value of type '__NSCFString' (0x10e4d5ef0) to 'NSDictionary' (0x10e4d6bc0).'
}
ParseJson Function:
func parseJSON(inputData: AnyObject) -> Dictionary<String,AnyObject>?{
do {
let jsonDict = try NSJSONSerialization.JSONObjectWithData(inputData as! NSData, options:NSJSONReadingOptions.MutableContainers) as! Dictionary<String,AnyObject>
// use jsonData
return jsonDict
} catch let error as NSError {
// report error
print(error.description)
print("Session: Json Parse Error!!!")
return nil
}
}
This is the result of pirnt(jsonDict)
[data: {"session_id":"ab4kn9fj34ko89kjkl5ljs98gfk498fgkl409alk34l","user_info":{"username":"Johny Cage","ENCPASSWORD":"johnycage","id":1,"FULLNAME":"Johny Cage"}}, status: Success]
Any help or suggestion is highly appreciated.
Check your return data from web-service. I think you are converting it in Jason String multiple times, Or something like this. There is no issue in above code. Check your server side.

How to fix `Ambiguous use of 'subscript'` every time?

I'm using this class that was written in Swift 1.2 and now I want to use it with Swift 2.0.
I get an error: Ambiguous use of 'subscript' # let artist = result["name"] as! String
} else if let jsonArtists = jsonResult["artists"] as? NSDictionary {
if let results:NSArray = jsonArtists["items"] as? NSArray {
dispatch_async(dispatch_get_main_queue(), {
self.searching = false
var suggestionResults: [spotifySearchResult] = []
for result in results {
let artist = result["name"] as! String
var sugresult = spotifySearchResult()
sugresult.artist = artist
if !suggestionResults.contains(sugresult) {
suggestionResults.append(sugresult)
}
}
handler(suggestionResults)
})
}
}
}
I tried different fixes such as let artist = (result["name"] as! String) or let artist = (result["name"] as! String) as! String
But nothing worked.
I know that the question was already post 4 times but, I can't find anyone explaining how to fix it in every case, only case by case.
Can someone explain me how to investigate to fix it? Not just only a fix for my case. I would prefer fix it by myself with your hints!
BTW what does mean subscript? Is subscript the thing between quotation mark? IMHO the error message is a bit vague...
EDIT:
class spotifySearchResult : NSObject {
var artist=""
var track=""
var duration=0
var spotifyURL = NSURL()
var spotifyURI = NSURL()
override func isEqual(theObject: AnyObject?) -> Bool {
if let myObject = theObject as? spotifySearchResult {
return (myObject.artist.uppercaseString == self.artist.uppercaseString && myObject.track.uppercaseString == self.track.uppercaseString)
}
return false
}
}
Subscription means to use the shorter syntax item["key"] for item.objectForKey["key"]
results seems to be an array of dictionaries so I suggest to cast down to a more specific type
if let results = jsonArtists["items"] as? [[String:AnyObject]] {
or even, if all values are guaranteed to be strings
if let results = jsonArtists["items"] as? [[String:String]] {

Xcode 7 Error Code "Cannot convert value type([AnyObject]

Heres a copy of my code where the error is giving me, the error is on the line where it says query.findobjectsInBackgroundWithBlock. The full error message is this: `Cannot convert value type ([AnyObject]!, NSError!) -> Void to expected argument type 'PFQueryArrayResultBlock?'
// Retrieve Messages
func retrieveMessages() {
// Create a new PFQuery
var query:PFQuery = PFQuery(className: "Message")
// Call findobjectsinbackground
query.findObjectsInBackgroundWithBlock {(objects:[AnyObject]!, error:NSError!) -> Void in
// Clear the messagesArray
self.messageArray = [String]()
// Loops through the objects
for messageObject in objects {
// Retrieve the text column value of each PFObject
let messageText:String? = (messageObject as! PFObject)["Text"] as? String
// Assign it into our messagesArray
if messageText != nil {
self.messageArray.append(messageText!)
}
}
// Reload the tableview
self.messageTableView.reloadData()
}
}
The method signature had improved in Swift 2.0 with Parse SDK 1.10.0. Replace [AnyObject]! with [PFObject]?. [PFObject] is an optional because Swift doesn't know if it will exist or not.
func retrieveMessages() {
var query:PFQuery = PFQuery(className: "Message")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
self.messageArray = [String]()
for messageObject in objects {
let messageText:String? = (messageObject as! PFObject)["Text"] as? String
if messageText != nil {
self.messageArray.append(messageText!)
}
}
self.messageTableView.reloadData()
}
}

Passing Dictionary to Watch

I'm trying to pass data from iPhone -> Watch via Watch Connectivity using background transfer via Application Context method.
iPhone TableViewController
private func configureWCSession() {
session?.delegate = self;
session?.activateSession()
print("Configured WC Session")
}
func getParsePassData () {
let gmtTime = NSDate()
// Query Parse
let query = PFQuery(className: "data")
query.whereKey("dateGame", greaterThanOrEqualTo: gmtTime)
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objectsFromParse = objects as? [PFObject]{
for MatchupObject in objectsFromParse
{
let matchupDict = ["matchupSaved" : MatchupObject]
do {
try self.session?.updateApplicationContext(matchupDict)
print("getParsePassData iPhone")
} catch {
print("error")
}
}
}
}
}
}
I'm getting error twice printed in the log (I have two matchups in Parse so maybe it knows there's two objects and thats why its throwing two errors too?):
Configured WC Session
error
error
So I haven't even gotten to the point where I can print it in the Watch app to see if the matchups passed correctly.
Watch InterfaceController:
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
let matchupWatch = applicationContext["matchupSaved"] as? String
print("Matchups: %#", matchupWatch)
}
Any ideas? Will post any extra code that you need. Thanks!
EDIT 1:
Per EridB answer, I tried adding encoding into getParsePassData
func getParsePassData () {
let gmtTime = NSDate()
// Query Parse
let query = PFQuery(className: "data")
query.whereKey("dateGame", greaterThanOrEqualTo: gmtTime)
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objectsFromParse = objects as? [PFObject]{
for MatchupObject in objectsFromParse
{
let data = NSKeyedArchiver.archivedDataWithRootObject(MatchupObject)
let matchupDict = ["matchupSaved" : data]
do {
try self.session?.updateApplicationContext(matchupDict)
print("getParsePassData iPhone")
} catch {
print("error")
}
}
}
}
}
}
But get this in the log:
-[PFObject encodeWithCoder:]: unrecognized selector sent to instance 0x7fbe80d43f30
*** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
EDIT 2:
Per EridB answer, I also tried just pasting the function into my code:
func sendObjectToWatch(object: NSObject) {
//Archiving
let data = NSKeyedArchiver.archivedDataWithRootObject(MatchupObject)
//Putting it in the dictionary
let matchupDict = ["matchupSaved" : data]
//Send the matchupDict via WCSession
self.session?.updateApplicationContext(matchupDict)
}
But get this error on the first line of the function:
"Use of unresolved identifer MatchupObject"
I'm sure I must not be understanding how to use EridB's answer correctly.
EDIT 3:
NSCoder methods:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
//super.init(coder: aDecoder)
configureWCSession()
// Configure the PFQueryTableView
self.parseClassName = "data"
self.textKey = "matchup"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
Error
You are getting that error, because you are putting a NSObject (MatchupObject) which does not conform to NSCoding inside the dictionary that you are going to pass.
From Apple Docs
For most types of transfers, you provide an NSDictionary object with
the data you want to send. The keys and values of your dictionary must
all be property list types, because the data must be serialized and
sent wirelessly. (If you need to include types that are not property
list types, package them in an NSData object or write them to a file
before sending them.) In addition, the dictionaries you send should be
compact and contain only the data you really need. Keeping your
dictionaries small ensures that they are transmitted quickly and do
not consume too much power on both devices.
Details
You need to archive your NSObject's to NSData and then put it in the NSDictionary. If you archive a NSObject which does not conform to NSCoding, the NSData will be nil.
This example greatly shows how to conform a NSObject to NSCoding, and if you implement these things then you just follow the code below:
//Send the dictionary to the watch
func sendObjectToWatch(object: NSObject) {
//Archiving
let data = NSKeyedArchiver.archivedDataWithRootObject(MatchupObject)
//Putting it in the dictionary
let matchupDict = ["matchupSaved" : data]
//Send the matchupDict via WCSession
self.session?.updateApplicationContext(matchupDict)
}
//When receiving object from the other side unarchive it and get the object back
func objectFromData(dictionary: NSDictionary) -> MatchupObject {
//Load the archived object from received dictionary
let data = dictionary["matchupSaved"]
//Deserialize data to MatchupObject
let matchUpObject = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! MatchupObject
return matchUpObject
}
Since you are using Parse, modifying an object maybe cannot be done (I haven't used Parse in a while, so IDK for sure), but from their forum I found this question: https://parse.com/questions/is-there-a-way-to-serialize-a-parse-object-to-a-plain-string-or-a-json-string which can help you solve this problem easier than it looks above :)

Swift optional chaining with NSDictionary

Please help to remake this
if let field = parent_obj?.getFieldForCode(code) {
if let stored_value = field["value"] as? String {
into optional chaining syntax in single line. I tried to do it like this:
let stored_value = parent_obj?.getFieldForCode(code)?["value"] as? String
and got an error:
Type 'String' does not conform to protocol 'NSCopying'
This is my function header:
func getFieldForCode(code: String) -> NSDictionary?
Is it possible? I ask it because any time I work with NSArrays and NSDictionaries my code looks terrible:
if let code = self.row_info["code"] as? String {
if let value_field = self.row_info["value_field"] as? String {
if let field = parent_obj?.getFieldForCode(code) {
if let stored_value = field["value"] as? String {
if let fields = self.fields_set{
if let current_value = fields[indexPath.row][value_field] as? String {
Any advices?
You can't cast it directly to a String because you're pulling it from an NSDictionary and, like the error says, String doesn't conform to NSCopying. However, String is bridged to NSString, and NSString does conform to NSCopying. So, with a little bit of casting/bridging trickery, you can make it work like this:
let stored_value: String? = parent_obj?.getFieldForCode(code)?["value"] as? NSString
Note: If you're using this in an optional binding (which it looks like you want to), don't forget to drop the ? from stored_value's type declaration:
if let stored_value: String = parent_obj?.getFieldForCode(code)?["value"] as? NSString {
/* ... */
}

Resources