Format String in Swift - ios

I have a String saved in an NSDictionary named accountInfoDict that I received from my iPhone app. I want to show this string using Swift in my watch kit app.
This is how I am trying to display the string:
self.pointsLabel.setText(String(format: "%# points",
arguments: accountInfoDict!["points"] as? String))
I get an error message saying:
Cannot convert value of type 'String?' to expected argument type '[CVarArgType]'
Does anyone know what this means and how I can format my string to make this work? Thanks!
Note:
The string displays correctly when I do it like this:
self.pointsLabel.setText(accountInfoDict!["points"] as? String)
But I want to add "points" to the end of the string.

You can just achieve it by writing it like:
// If point is nil, shows 0
let point = accountInfoDict!["points"] as? String ?? "0"
self.pointsLabel.setText("\(point) Points")
Also you can write it as:
self.pointsLabel.setText(String(format: "%# points", arguments: [point]))
More conveniently:
self.pointsLabel.setText(String(format: "%# points", point))

Break it into 2 lines:
let points = accountInfoDict!["points"] as! String
self.pointsLabel.setText(String(format: "%# points",points))
You can also usestring interpolation in Swift:
self.pointsLabel.setText("\(accountInfoDict!["points"]!) points")

Related

Get String value from an optional in Swift 4

I am new to Swift and am trying to compare my Error description name with different String constants to show the user different results, based on the error.
I am using:
let errorName = errors.first?["name"].debugDescription
The value of errorName comes as "Optional(AlreadyActiveUser)" and when i compare this to my constant string "AlreadyActiveUser", i get false.
I have tried many things, but i am not able to get the value of the string inside the optional.
Someone, please help.
You can use optional binding in this case...
guard let errorName = errors.first?["name"].debugDescription as? String {
print("value is not present...")
return
}
print(errorName)
//here you can compare errorName == "AlreadyActiveUser"
you can use this
if let errorName = errors.first?["name"] as? String {
print(errorName)
//here you can compare errorName == "AlreadyActiveUser"
}
else
{
print("value is not present...")
}
try let errorName = errors.first!["name"].debugDescription
Notes that I forced wrapping first with ! instead of ?.

Swift converting string to double with numberformatter returns nil

I am trying to convert the value of a text field, which the user enters. As users are able to enter decimal values in european number format too, I use numberformatter for that. This was what I was trying:
let newprice = MaximumPriceLabel.text as! String
print(newprice) -> result: Optional("10,00")
print(formatter.number(from: newprice as String)) -> result: nil
print(Double(formatter.number(from: ("10,11"))!)) -> result: 10.11 -> that is what I want
So there is a value stored in the variable newprice, but when formatting, it returns nil. When I test it with a manual value, it works. Is there anything I am doing wrong? Formatter.local is set to Locale.current.
Update: The problem seems to be that the MaximumPriceLabel.text contains not only the value I need, but really the text "Optional("10,00") - which fails when converting to a number. The value is filled like this:
self.MaximumPriceLabel.text = String(describing: formatter.string(from: NSNumber(value: desprice)))
and when I do a print afterwards, I receive "Optional("Optional(\"10,00\")")" -> even when I clear the variable MaximumPriceLabel.text first.
You need to learn how to deal with optionals.
Your first issue is how you set the label's text. Please note that NumberFormatter string(from:) returns an optional String. And never, never use String(describing:) to display information to a user. That should only be used for debugging.
Start by changing:
self.MaximumPriceLabel.text = String(describing: formatter.string(from: NSNumber(value: desprice)))
to:
if let text = formatter.string(from: NSNumber(value: desprice)) {
MaximumPriceLabel.text = text
}
That will fix the issue of the label's text having the text Optional(...).
Then your code for converting the label's text back to a string needs to be updated as:
if let newprice = MaximumPriceLabel.text {
if let price = formatter.number(from: newprice) {
print("The price is \(price)")
} else {
print("Invalid number: \(newprice)")
}
}

iOS Swift: Could not cast value type '__NSCFNumber' to 'NSString'

I am retrieving a number value from my Firebase database (JSON db) and then displaying this number into a textField, although I get this error when I try to display it.
Could not cast value type '__NSCFNumber' to 'NSString'
How can I properly convert the retrieved value to a String, taking into consideration that this value maybe change between a String and a Number when I retrieve it.
Here is my code:
let quantity = child.childSnapshot(forPath: "quantity").value // Get value from Firebase
// Check if the quantity exists, then add to object as string.
if (!(quantity is NSNull) && ((quantity as! String) != "")) {
newDetail.setQuantity(quantity: quantity as! String)
}
The error is saying that your quantity is Number and you cannot directly convert number to String, try like this.
newDetail.setQuantity(quantity: "\(quantity)")
Or
if let quantity = child.childSnapshot(forPath: "quantity").value as? NSNumber {
newDetail.setQuantity(quantity: quantity.stringValue)
}
else if let quantity = child.childSnapshot(forPath: "quantity").value as? String {
newDetail.setQuantity(quantity: quantity)
}
Or With Single if statement
if let quantity = child.childSnapshot(forPath: "quantity").value,
(num is NSNumber || num is String) {
newDetail.setQuantity(quantity: "\(quantity))
}
Using second and third option there is no need to check for nil.
Swift 4:
let rollNumber:String = String(format: "%#", rollNumberWhichIsANumber as! CVarArg)
You may convert your NSNumber value to string like this too, its more traditional and basic approach to format a string
newDetail.setQuantity(String(format: "%#", quantity))
Swift 4.
newDetail.setQuantity(String(describing: rollNumberWhichIsANumber))
In swift 4.1 and Xcode 9.4.1
newDetail.setQuantity(quantity: "(quantity)")
We can convert to string like this "\(quantity)"
let session_id : Int32 = (jsonObject.value(forKey: "id") as! NSNumber).int32Value
Swift 5:
I manage to fix it buy using .description when interpolating the UserDefaults value into a label converting from Int to String.
working code
highScoreLabel?.text = "HiScore: \(hiScoreValue.description)"
old code
highScoreLabel?.text = "HiScore: \(String(describing: hiScoreValue))"

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

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
}

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