How do I get Parse data as a String out of PFUser? - ios

I am currently trying to get a value called "loot" out of the current user. I need the value as a String, but Swift is being stubborn and says it "cannot convert Anyobject to String". The Parse documentation for iOS says to use something like:
let score = gameScore["score"] as String
and so, I try this :
let lootAmount = user["loot"] as String
BTW 'user' is referring to the current user. When I try that, it gives error saying it's not convertible. I tried placing '!'s and '?'s wherever Xcode suggested, but it just crashed the app with no error.
So, how do I get the user value called "loot" as a String?

Loot is an NSNumber not an NSString or String.
You could convert it to a String like this:
if let loot = user["loot"] as? NSNumber {
let lootString = "\(loot)"
}
If you're not sure of an object's type, you can ask it using dynamicType:
print(user["loot"]!.dynamicType)
//prints `__NSCFNumber.Type`

You may need to downcast AnyObject. Try this: let lootAmount = user["loot"] as? String or unwrap your optional user if you haven't done so:
let currentUser = PFUser.currentUser()
if let user = currentUser {
let lootAmount = user["loot"] as String
}

Related

Swift 3 optional string to int

I am using Vapor for Swift backend. Following is the code i am working with.
drop.post("postTodo") { request in
var jsonContent: JSON?
if let contentType = request.headers["Content-Type"], contentType.contains("application/json"), let jsonData = request.json {
jsonContent = jsonData
print("Got JSON: \(jsonContent)")
}
guard let id = jsonContent?.node.object?["id"]?.string
else {
return JSON(["message": "Please include mandatory parameters"])
}
let tempId = Int(id)!
I am getting "id" as optional string for eg: Optional("123") for jsonContent?.node.object?["id"]?.string
When I try to convert it to int using Int(id)! i get back nil
If i try to do let tempId = Int(id!) it gives error.
But when i do the same thing in playground i get proper int value.
let id: String?
id = "1234"
let myInt = Int(id!)
Why Optional string to Int is not working properly in my Vapor app ?
Any idea.
If "id" is an optional string, then you probably don't want to be force unwrapping it with the "!".
The safest approach would be something like:
if let id = id
{
let myIdAsInt = Int(id)
}
The reason it "works" in the playground, is you are definitely assigning a non-nil value to the string (therefore you get away with the force unwrap).
String!might contain a string, or it might contain nil. It’s like a regular optional, but Swift lets you access the value directly without the unwrapping safety. If you try to do it, it means you know there’s a value there – but if you’re wrong your app will crash.
var optionalString: String? = "123"
// first check if it doesn't contain nil
if let str = optionalString {
// string to -> Int
if let id = Int(str) {
print(id) // work with id
}
} else {
// optionalString contains nil
}
what i found is in my iOS code i had a struct with optional properties coz of which when mapped to Dict gave object with optional values to keys.
If I make properties non optional and send it to vapor backend after it works fine.
So basically it was the case of using Optionals properly.

Swift realm.io can get object property using object.getValueForKey("key") but not as object.key

I am trying since a whole day migrating my localStorage data to realm.io...
Now the only issue I am facing is that I can get the object property using
object.valueforKey("key")
but not using the simpler one
object.key
Here you have a peace of my code
let realm = try! Realm()
let predicate = NSPredicate(format: "groupID = %#", group.valueForKey("groupID") as! String )
let current = realm.objects(apiGroup).filter(predicate)
let currentGroup = current[0]
print(currentGroup.valueForKey("token") as! String)
print(currentGroup.token)
When I execute that this is been printed on the console.
56abbf408cfea7941a8b30b7
fatal error: unexpectedly found nil while unwrapping an Optional value
Can you please tell me if this is the normal behaviour or if I can do something to get the
"object.key"
notation??
Thanks in advance
Thanks all for your views. I ended up creating a custom object with a custom init and passing realm object to it...
Then I looped the realm object to assign the same object properties to the custom one... example
class Images:Object{
var picid:String = ""
var path:String = ""
var timeStamp:NSDate!
override class func primaryKey() -> String{
return "picid"
}
}
class realmImages{
var picid:String!
var path:String!
var timeStamp:NSDate!
init(object:Images){
picid = object.valueForKey("picid") as! String
path = object.valueForKey("path") as! String
timeStamp = object.valueForKey("timeStamp") as! NSDate
}
}
Hang on! I think I didn't actually understand the question properly!
If the .token property is actually a member of your class, that should absolutely work. Just to confirm, are you defining your members of your Realm model subclass properly, according to the documentation?
class APIGroup: Object {
dynamic var token = ""
}
If so, and you're STILL having trouble, it may be possible that Swift wasn't able to infer that the type of the object returned from the filter wasn't your APIGroup object (Which would explain why valueForKey still works).
If that's the case, stating the type should help:
let currentGroup = current[0] as APIGroup
Let me know if that helped!

SWIFT access nested dictionary

I have a Dictionary that has a User object, and that User object is a dictionary that has a key "Name".
In Swift, i need to access the value for "Name".
So I did the following:
let user = question[kUserOwner] as! PFUser
let userName = user[kName] as! String
userButton.setTitle(userName, forState:UIControlState.Normal)
1) Is there really no easier/shorter way to do this?
In Objective C:
[_userButton setTitle:[[question objectForKey:kUserOwner] objectForKey:kName] forState:UIControlStateNormal];
I do realize that it is not Type safe but I can live with that, as long as I know what I am doing.
2) Is there any way i can avoid casting?
When you subscript, you get an Optional. And you cannot subscript an Optional. Therefore, while you can perhaps avoid casting, you cannot avoid unwrapping:
let dinner = ["name":"Matt"]
let douter = ["owner":dinner]
let name = douter["owner"]!["name"]
But that only works because Swift knows very specifically what douter is. It would be better, therefore, to do this in stages, as Swift expects you to do, e.g. with a nested series of if let bindings:
let dinner : AnyObject = ["name":"Matt"] as AnyObject
let douter : AnyObject = ["owner":dinner] as AnyObject
if let owner = douter["owner"] as? [NSObject:AnyObject],
let name = dinner["name"] as? String {
// do something with name
}

Why is array empty after appending object to it

I am working in a TableViewController that I am trying to fill up with data from a plist.
I declared this at the top:
var studentsArray:Array<StudentData>?
And now I am doing the following in a function that loads my plist:
var path = NSBundle.mainBundle().URLForResource("students", withExtension: "plist")
let tmpArray = NSArray(contentsOfURL: path!)
for studentDict in tmpArray!{
let name = studentDict["name"]as! String
let dateOfBirth = studentDict["dateOfBirth"] as! NSDate
let regular = studentDict["regular"] as! Bool
let photoFileName = studentDict["photoFileName"] as! String
let data = StudentData(name : name, dateOfBirth: dateOfBirth, regular : regular, photoFileName: photoFileName)
self.studentsArray?.append(data)
println(studentsArray!.count)
}
I tried logging the properties of the Object, they are all being filled in, but it goes wrong at the .append and somehow it just won't do that. The array's count remains 'Nil' when logged.
I'm kind of lost here! Any help is appreciated.
Doesn't look like you are initializing studentsArray anywhere. Make sure to do that. For the record, array.count should be 0 if the array is empty, not nil. If you are seeing nil that means the array is probably nil (aka you didnt initialize it).
Try changing your array declaration to this and let me know if it works. Hope it helps:
var studentsArray:Array<StudentData>? = Array<StudentData>()

Swift optionals: language issue, or doing something wrong?

I am doing what I believe to be a very simple task. I'm trying to get a value out of a dictionary if the key exists. I am doing this for a couple keys in the dictionary and then creating an object if they all exist (basically decoding a JSON object). I am new to the language but this seems to me like it should work, yet doesn't:
class func fromDict(d: [String : AnyObject]!) -> Todo? {
let title = d["title"]? as? String
// etc...
}
It gives me the error: Operand of postfix ? should have optional type; type is (String, AnyObject)
HOWEVER, if I do this, it works:
class func fromDict(d: [String : AnyObject]!) -> Todo? {
let maybeTitle = d["title"]?
let title = maybeTitle as? String
// etc...
}
It appears to be basic substitution but I may be missing some nuance of the language. Could anyone shed some light on this?
The recommended pattern is
if let maybeTitle = d["title"] as? String {
// do something with maybeTitle
}
else {
// abort object creation
}
It is possibly really a question of nuance. The form array[subscript]? is ambiguous because it could mean that the whole dictionary (<String:AnyObject>) is optional while you probably mean the result (String). In the above pattern, you leverage the fact that Dictionary is designed to assume that accessing some key results in an optional type.
After experimenting, and noticing that the ? after as is just as ambiguous, more, here is my solution:
var dictionary = ["one":"1", "two":"2"]
// or var dictionary = ["one":1, "two":2]
var message = ""
if let three = dictionary["three"] as Any? {
message = "\(three)"
}
else {
message = "No three available."
}
message // "No three available."
This would work with all non-object Swift objects, including Swift Strings, numbers etc. Thanks to Viktor for reminding me that String is not an object in Swift. +
If you know the type of the values you can substitute Any? with the appropriate optional type, like String?
There are a few of things going on here.
1) The ? in d["title"]? is not correct usage. If you're trying to unwrap d["title"] then use a ! but be careful because this will crash if title is not a valid key in your dictionary. (The ? is used for optional chaining like if you were trying to call a method on an optional variable or access a property. In that case, the access would just do nothing if the optional were nil). It doesn't appear that you're trying to unwrap d["title"] so leave off the ?. A dictionary access always returns an optional value because the key might not exist.
2) If you were to fix that:
let maybeTitle = d["title"] as? String
The error message changes to: error: '(String, AnyObject)' is not convertible to 'String'
The problem here is that a String is not an object. You need to cast to NSString.
let maybeTitle = d["title"] as? NSString
This will result in maybeTitle being an NSString?. If d["title"] doesn't exist or if the type is really NSNumber instead of NSString, then the optional will have a value of nil but the app won't crash.
3) Your statement:
let title = maybeTitle as? String
does not unwrap the optional variable as you would like. The correct form is:
if let title = maybeTitle as? String {
// title is unwrapped and now has type String
}
So putting that all together:
if let title = d["title"] as? NSString {
// If we get here we know "title" is a valid key in the dictionary, and
// we got the type right. title has now been unwrapped and is ready to use
}
title will have the type NSString which is what is stored in the dictionary since it holds objects. You can do most everything with NSString that you can do with String, but if you need title to be a String you can do this:
if var title:String = d["title"] as? NSString {
title += " by Poe"
}
and if your dictionary has NSNumbers as well:
if var age:Int = d["age"] as? NSNumber {
age += 1
}

Resources