Unwrapping a Int to String cast in Swift - ios

I am gathering an NSNumber from my plist and I want to print that in a String:
let tijd = String(self.sortedHighscores[indexPath.row]["Tijd"]!)
cell.detailTextLabel?.text = "\(tijd) seconden"
But in Simulator I'm seeing printed: Optional(120) seconden for example.
How do I solve this? I've tried unwrapping tijd, but that would result in errors in the compiler telling me to delete the !.

Try this:
var highscore : NSNumber = self.sortedHighscores[indexPath.row]["Tijd"] as! NSNumber
var a : String = String(format:"%d",highscore.integerValue)
cell.detailTextLabel.text = a

tijd being an optional, you need to unwrap it, but you should check whether it has a value, too.
if let foo = tijd {
cell.detailTextLabel?.text = "\(foo) seconden"
}
If you know it will always have a value, "\(tijd!) seconden" should work also.

Related

UILabel shows Optional("P")

I have a UILabel where i set its texts property, and
let firstCharacter: String = "\(user.name.characters.first)" ?? ""
print(firstCharacter)
userNameLabel.text = firstCharacter
Output: Optional("P")
String Interpolating user.name.characters.first will always create a String because even if user.name.characters.first is nil then the interpolated string will be "nil".
The correct solution is
userNameLabel.text = "" //set the default value as ""
//if the name contains atleast one char then set it
if let firstCharacter = user.name.characters.first {
userNameLabel.text = "\(firstCharacter)"
}
Wrap optional like so:
if let userName = user.name.characters.first {
userNameLabel.text = userName
}
IF you need to get first character you can use following code and it would be more correct than taking first character
let firstCharacter = user.name.substringToIndex(user.name.startIndex.advancedBy(1))
But note that you need to check before this call if the string is not empty.
Print like this.
println(firstCharacter!)
it will work.

Swift: Cannot convert from string to int (using slider tag)

let device = devices[indexPath.row]
let deviceTag = device["deviceID"] as? String
cell.slider.tag = deviceTag
I get an error from the above: Cannot assign value of type 'String?' to type 'Int'
This doesn't work (below):
cell.slider.tag = Int(deviceTag)
or what "fix-it" provides:
cell.slider.tag = Int(deviceTag!)!
You need to set optional while casting from string. Try the below code.
let device = devices[indexPath.row]
let deviceTag = device["deviceID"] as! String
cell.slider.tag = Int(deviceTag)
Unless you're 100% sure the value of the dictionary device is an Int you shouldn't implicitly unwrap those optionals.
You can use:
if let deviceTag = deviceTag, tag = Int(deviceTag) { cell.slider.tag = tag }
or
cell.slider.tag = Int(deviceTag) ?? 0
But looking at your examples, it seems like deviceTag isn't a number at all. Perhaps you should look in your debug area (left panel) to see what the value is or simply print(deviceTag) to see what the value is.

What is the difference between " as string" and "stringvalue" in swift?

I have a code :
var i : AnyObject!
i = 10
println(i as String)
println(i.stringValue)
it get crashed on as String line but runs in second i.stringValue.
What is the difference between as String and stringValue in the above lines?
.stringValue is a way to extract Integer into string value but as String will not work for that And if you use as String then Xcode will force you to add ! with as which is not good and it will never succeed and it would crash your app. you can't cast Int to String. It will always fail. Thats why when you do as! String it crashes the app.
So casting is not a good idea here.
And here is some more ways to extract Integer into string value:
let i : Int = 5 // 5
let firstWay = i.description // "5"
let anotherWay = "\(i)" // "5"
let thirdWay = String(i) // "5"
Here you can not use let forthway = i.stringValue because Int Doesn't have member named stringValue
But you can do same thing with anyObject as shown below:
let i : AnyObject = 5 // 5
let firstWay = i.description // "5"
let anotherWay = "\(i)" // "5"
let thirdWay = String(i) // "5"
let forthway = i.stringValue // "5" // now this will work.
Both are casting an Int to String but this will not work anymore.
In Swift 2 its not possible to do it like that.
U should use:
let i = 5
print(String(format: "%i", i))
This will specifically write the int value as a String
with as String, you can not cast the value but you define that the variable contains String but in you case it is Int.so it crashes.
while the other way i.e. of i.stringValue cast your value into String.So it doesn't gives you any crash and successfully cast into String value.
Note: As you are using AnyObject, variable have member stringvalue...but Int doesn't have...To cast Int value check out #Dharmesh Kheni answer

(SKNode) not convertible to string (it was working with old xCode)

In my apps I was using this piece of code and it worked perfectly:
var data3: NSArray = [] //1
for gg in data3{ //2
var hh:String = gg["percentage"] as String //3
perchomerec = hh.toInt()! //4
}
Now I updated my xCode and OSx version and now this same piece of code gives this error (on line //3):
[SKNode] is not convertible to String
What do I have to change?
Since Swift 1.2 as operator can only be used for upcasting. When downcasting, you should use as! or as? (detailed description can be found e.g. in The Swift Programming Language).
var hh:String = gg["percentage"] as! String
data3 seem to be of type [[String:Int]] based on your responses on my comments.
So by changing NSArray to [[String:Int]] or just simply removing NSArray completely and letting Swift determine the type by itself.
I guess your question is in pseudo-code so my guess is how you set that data3's data:
let data3 = [["percentage" : 33]] // Swift will determine this type to: [[String:Int]]
for gg in data3 { // gg will become [String:Int]
perchomerec = gg
}
Or if you still want the NSArray type then to cast gg in a for loop you have to cast the array itself:
for gg in data3 as! [[String:Int]]
Edit
If the array changes then it has to be an NSArray or [AnyObject] and then you have to test to cast for every possible type.
for gg in data3 {
if let dict = gg as? NSDictionary {
if let str = dict["percentage"] as? String, nr = str.toInt() {
perchomerec = nr
}
else if let nr = dict["percentage"] as? Int {
perchomerec = nr
}
}
}
It sounds like you need to use ! or ?, although from Jakub Vano's answer it sounds like using optional unwrapping would be more suitable for your code. If you don't expect hh to not be a String or not be nil then I also suggest you check your code elsewhere.
var data3: NSArray = []
for gg in data3 {
if let h = hh as? String {
perchomerec = h.toInt()!
}
}

swift ios: different errors for similar data .. very strange

Something strange is happening.
I have this in my TableDataArray:
(
{
count = 0;
title = Open;
},
{
count = 20;
title = Closed;
},
{
count = 0;
title = Pending;
},
{
count = 10;
title = Queue;
}
)
When I do just:
var rowData: NSDictionary = TableDataArray[indexPath.row] as NSDictionary
var maintext: String? = rowData["title"] as NSString
println(maintext)
if (maintext != nil ){
cell.textLabel.text = maintext
}
it works, I see the titles in my table.
But as soon as I add these lines:
var detailtext: String? = rowData["count"] as NSString ## tried also as Int, NSInteger, similar fate
println(detailtext)
if (detailtext != nil) {
cell.detailTextLabel.text = detailtext
}
The app crashes with "Swift dynamic cast failed", and I am unable to figure out why.
Another is if I make another API call, and there, the results are similar, but instead of crashing, it just displays... both the text and detailtext.
Yet in another api call, it crashes, but with 'fatal error: unexpectedly found nil while unwrapping an Optional value'... and yet in another one, it simply says String is not convertible to Uint8...
And this is bugging me. Same API calls, similar results, but it works in one, and crashes with different results...
So question is, how do I detect and troubleshoot such issues, and then display the detailText... because the values are there.
Thanks.
Your value can't be an Int or a String because values in NSDictionarys have to be objects. Your count is an NSNumber which is an object wrapper around a basic number type.
To safely extract the number from your NSDictionary use this style:
if let count = rowData["count"] as? NSNumber {
// If I get here, I know count is an NSNumber. If it were some other type
// it wouldn't crash, but I wouldn't get to this point.
cell.detailTextLabel.text = "\(count)"
}
This protects you from a whole host of problems. When you ask for an item from an NSDictionary, it is possible the key doesn't exist in the dictionary, and in that case the result will be nil. If you attempt to cast this directly to an expected type, you will get the fatal error: unexpectedly found nil while unwrapping an Optional value message. With the above style, the nil is handled gracefully and no error results, you just don't enter the block.
It appears that your count can have various types. You can use a switch to handle this in a cleaner way:
switch rowData["count"] {
case let count as NSNumber:
cell.detailTextLabel.text = "\(count)"
case let count as NSString:
cell.detailTextLabel.text = count
case nil:
println("value not in dictionary")
default:
println("I still haven't identified the type")
}
This worked:
if let maintext = rowData["title"] as? NSString {
println(maintext)
cell.textLabel.text = maintext
}
if var count = rowData["count"] as? NSNumber {
// If I get here, I know count is an NSNumber. If it were some other type
// it wouldn't crash, but I wouldn't get to this point.
println("\(count)")
cell.detailTextLabel.text = "\(count)"
}
if var count = rowData["count"] as? String {
// If I get here, I know count is an NSNumber. If it were some other type
// it wouldn't crash, but I wouldn't get to this point.
println(count)
cell.detailTextLabel.text = count
}
But is this correct way ?

Resources