Swift: Convert Int to UInt32, and how to unwrap optional - ios

im pretty new to swift, and im just trying to build something to test out the waters. this is in relation to a previous question i had. I am building some code to take user input from a UITextField object, and basically im trying to figure out how to convert an Int to a UInt32, but nothing ive searched on SO or otherwise has really helped.
here is my code
//this is where i call the user input.
var rangeInput: Int? {
get {
return Int(rangeInputTextField?.text ?? "")
}
//this is my function to create a range, and call a random number out of that range
let viewController = ViewController()
var x = ViewController().rangeInput
let y = (Int?(x!))
var number = arc4random_uniform(Int(y!))//ERROR OCCURS HERE "Cannot convert value of type 'Int' to expected argument type 'UInt32'
//MARK: Class for random number
struct RandomNumber {
// numberRange to change the value for 1...X(user input)
//creates the list to be picked from. (pickRandom)
func numberRange(high: UInt32) ->Range<UInt32>{
if let high = UInt32?(0){
print("Invalid number")
} else { let high = Int(y!) + 1
}
let range = 1...high
return range
}
//pick random number from that list
let pickRandom = number
}
edit: Converted UInt, using answer in comments, but am having an issue with unwrapping optionals.
am I doing something wrong with forcibly unwrapping optionals?

let viewController = ViewController()
var x = ViewController().rangeInput
var number = arc4random_uniform(UInt32(x!)) // <----- UInt32 conversion
However, do recommend to check the user input x and/or after the UInt32 conversion, in case user inputs something not sensible, using guard or if let

Initializers are called in swift by listing the data type (UInt32 in this case) followed by parenthesis containing the parameters. For most basic data types in Swift, there are no parameters for the initializers. So if you ever want to make an Int, Float, Double, UInt32, String etc., just do
UInt32(Value)!//UInt32 can be substituted for any of the above values
The "!" unwraps the optional, and will result in an error in runtime like "unexpectedly found nil when unwrapping optional value" if the value is not a valid form of the data type, if you want to do this safely, you can do this
if UInt32(Value) != nil {
//Valid Value
}else {
//Invalid Value
}
Also this is unrelated to the question, but your if let statement will always be true because you are overriding the value of the parameter "high" to a UInt32 of 0. I could be wrong though.

Related

Cannot assign value of type 'String?' to type 'Int'

I am getting the error message Cannot assign value of type 'String?' to type 'Int'
I have browsed through other questions like this but it still shows the error.
if sunscreenName.text != nil && reapplyTime.text != nil {
sunscreen = sunscreenName.text!
reApplyTime = reapplyTime.text
//Some sort of message such as Progress hud
}
Thanks in advance!
I got your problem, actually what happens here Swift is is type safe langauge
So what you are doing is is to store a String value in Int which will not happen automatically you need to convert it to Int
like this
Int(sunscreenName.text)
But there is a catch there not all string are convertible to Int type, fo e.g.
let name = "roshan"
if you try to convert it to Int it will give you a nil
let a = Int(name)
So its better you do a optional Binding here provided by Swift
if let sunValue = Int(sunscreenName.text),let reApplyValue = Int(reapplyTime.text) {
sunscreen = sunValue
reApplyTime = reApplyValue
}
I recommend reading through The Swift Programming Language to get a better understanding of Swift and its fundamental concepts, since this question is fairly basic.
You make several mistakes:
if sunscreenName.text != nil && reapplyTime.text != nil {
This is wrong. In Swift, if you plan to use the value later, you should use if let rather than comparing to nil. Comparing to nil leaves the values optional, but if let unwraps them. So, do this instead:
if let sunscreenText = sunscreenName.text, let reapplyText = reapplyTime.text {
Now you have the sunscreenText and reapplyText variables, which are typed String, not String? (i.e. they are not optional).
Now, there's these two lines.
sunscreen = sunscreenName.text!
reApplyTime = reapplyTime.text
You don't say which one is giving the error, but the issue is the same in either case. First, use our unwrapped sunscreenText and reapplyText variables instead of sunscreenName.text! and reapplyTime.text. Next, if one of these is meant to be an Int instead of a String, cast it. Swift is not like JavaScript, in that it won't automatically convert values from one type to another, so if something is a string and we need an integer, we have to convert it ourselves.
(assuming reapplyTime was the line that was giving the error:)
if let reapplyInt = Int(reapplyText) {
reapplyTime = reapplyInt
}
The reason we have to unwrap is because Int(String) can return nil if the string is something that can't be converted to an integer. Alternately, we could just provide a default value:
reapplyTime = Int(reapplyText) ?? 0 // sets to 0 if it can't parse the string as an integer

Hangman Program 2

I have asked a question before about this program, but it seems that not all problems are resolved. I am currently experiencing an error that states: "Cannot convert value of type 'String' to expected argument type '_Element' (aka 'Character') on the "guard let indexInWord" line:
guard let letterIndex = letters.indexOf(sender)
else { return }
let letter = letterArray[letterIndex]
guard let indexInWord = word.characters.indexOf(letter)
else {
print("no such letter in this word")
return
}
// since we have spaces between dashes, we need to calc index this way
let indexInDashedString = indexInWord * 2
var dashString = wordLabel.text
dashString[indexInDashedString] = letter
wordLabel.text = dashString
I tried converting the String 'letter' to Character but it only resulted in more errors. I was wondering how I can possibly convert String to argument type "_Element." Please help.
It is hard to treat a string like a list in swift, mostly because the String.characters is not a typical array. Running a for loop on that works, but if you are looking for a specific character given an index, it is a bit more difficult. What I like doing is adding this function to the string class.
extenstion String {
func getChars() -> [String] {
var chars:[String] = []
for char in characters {
chars.append(String(char))
}
return chars
}
}
I would use this to define a variable when you receive input, then check this instead of String.characters

Trying to convert a hexadecimal text to a decimal in swift, but getting "Optional([num])" output

I am trying to convert a hexadecimal number to a decimal number. The user inputs a hexadecimal in a textview, on text edit action the decimal textview outputs the conversion. I am getting a strange behavior where the decimal textview is displaying "Optional[num]" IE "Optional(9) if I type in 9. Here is the hexadecimal text action listener:
#IBAction func inputHex(sender: AnyObject) {
if(Int(hexText.text!) != nil){
inputNumberText = hexText.text!
let st3 = Int(inputNumberText, radix: 16)
decText.text = String(st3)
}
}
let st3 = Int(inputNumberText, radix: 16)
calls the "failable initializer"
init?(_ text: String, radix radix: Int = default)
of struct Int, and that is failable for a good reason: It returns nil
if the string is not a valid number representation in the given base.
For example
Int("12XYZ", radix: 16)
Int("789", radix: 8)
would return nil. So st3 is an optional, and therefore String(st3)
is the string "Optional(...)".
But note that there are more issues with your code:
Don't use AnyObject parameters in action methods. Always use the
real type (in this case: UITextField) for better type checking.
Xcode has an option for that when you connect the action.
Never unwrap forcefully. Use optional binding instead.
Comparing against nil can and should be avoided in almost all
cases.
With regard to the last two points, compare When should I compare an optional value to nil?.
In your case
if (Int(hexText.text!) != nil)
is even wrong because it rejects valid hexadecimal strings like "ABCD".
This is how your action method could look like:
#IBAction func inputHex(sender: UITextField) {
if let text = sender.text,
let number = Int(text, radix: 16) {
decText.text = String(number)
}
}
Both let text = ... and let number = ... are optional bindings
in the context of the if-statement, and the if-block is only executed
if both bindings succeed.

How to use optional binding in Swift 2

I'm new to learning Swift so I decided I might as well learn Swift 2 instead. Everything has made sense to me so far except for the following code snippet. Hopefully someone can shed some light on this for me.
//: Playground - noun: a place where people can play
import UIKit
//Works
let possibleNumber="2"
if let actualNumber = Int(possibleNumber) {
print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
}
else {
print("could not be converted to integer")
}
//Doesn't Work and I'm not sure why
let testTextField = UITextField()
testTextField.text = "2"
let numberString = testTextField.text //I know this is redundant
if let num = Int(numberString) {
print("The number is: \(num)")
}
else {
print("Could not be converted to integer")
}
The top section of the code is straight from Apple's Swift 2 ebook and it makes sense to me how it uses optional binding to convert the string to an int. The second piece of code is basically the same except that the string comes from the text property of a UITextField. The bottom part of the code gives the following error:
Playground execution failed: /var/folders/nl/5dr8btl543j51jkqypj4252mpcnq11/T/./lldb/843/playground21.swift:18:18: error: value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?
if let num = Int(numberString) {
I fixed the problem by using this line:
if let num = Int(numberString!) {
I just want to know why the second example needs the ! and the first doesn't. I'm sure the problem has to do with the fact that I'm getting the string from a textfield. Thanks!
The difference is that in the first case possibleNumber is not an optional variable. It is definitely a string. It cannot be nil.
In the second case textField.text returns an optional string and so numberString is an optional variable. It could be nil.
Now... The conversion Int("") returns an optional int. if the string is "abc" then it cannot return a number so returns nil. This is what you are unwrapping with the if let... statement.
However, in the second case your string is also optional and the Int() will not accept an optional. So you are force unwrapping it. This is dangerous as it could crash the app if the string is nil.
What you could do instead is this...
if let numberString = textFeidl.text,
number = Int(numberString) {
// use the number
}
This will unwrap the text first and if it's available then use it to. Get the number. If that is not nil then you enter the block.
In Swift 2 you could use the guard let function here also.
Just seen that you are using Swift 2.
You can do it this way also...
func getNumber() -> Int {
guard let numberString = textField.text,
number = Int(numberString)
else {
return 0
}
return number
}

Reading from a dictionary in Swift - Not working

I am building a game in Xcode and I'm storing the details for the level in text files e.g. Level1.txt, Level2.txt etc.
I read in the data from a text file and store it in a Dictionary.
When I try to assign the values from the dictionary to the global variables, it doesn't work.
Text File Contents (Level1.txt)
LevelNum:1
weaponPickupRate:10.0
weaponPickupAmount:50.0
monsterMinSpeed:10.0
monsterMaxSpeed:15.0
monsterRate:1.0
totalMonsters:10.0
goldPerMonster:10
Global Variables
var settings = [String: Any]()
var monsterMaxSpeed = 0.0
Function For Obtaining Level Details
func GenerateLevel(levelNumber: Int) {
fileName = "level\(levelNumber).txt"
levelPath = "\(NSBundle.mainBundle().resourcePath!)/\(fileName)"
var err: NSError? = NSError()
let s = String(contentsOfFile: levelPath, encoding: NSUTF8StringEncoding, error: &err)
if let content = s {
var array = content.componentsSeparatedByString("\n")
for a in array {
var v = a.componentsSeparatedByString(":")
settings[v[0]] = v[1]
}
}
println(settings) // A
var e = settings["monsterMaxSpeed"]
println(e) // B
monsterMaxSpeed = settings["monsterMaxSpeed"] // C
}
Println(setting) (A) - prints:
[monsterRate: 1.0, monsterMinSpeed: 10.0, weaponPickupRate: 10.0, weaponPickupAmount: 50.0, goldPerMonster: 10, totalMonsters: 10.0, LevelNum: 1, monsterMaxSpeed: 15.0]
Println(e) (B) prints:
Optional("15.0")
This Line Does not work
it shows up an error and doesn't allow me to build my project. The Error given is:
'(String, Any)' is not convertible to 'Double'
monsterMaxSpeed = settings["monsterMaxSpeed"]
Please can someone help and advise me what I need to do?
Thanks,
Ryann
You have two problems here.
First, fetching from a [String:Any] dictionary by key does not return an Any. It returns an Any? i.e. an optional that may or may not contain an Any. This is because that key may not be present in the dictionary.
You need to test if the value is non-nil and unwrap the value if it is:
if let speed = settings["monsterMaxSpeed"] {
monsterMaxSpeed = speed
}
else {
// handle there being no speed setting in your file
// by reporting an error or similar
}
Or, if you’re happy with just using a default, you can use the nil coalescing operator:
// if the key is present, us the unwrapped value, if not use 0.0
monsterMaxSpeed = settings["monsterMaxSpeed"] ?? 0.0
Second, you’ve declared monsterMaxSpeed as a Double not an Any. So once you resolve your optional unwrapping problem you’ll get a second problem. You need to convert the Any to a Double using as?. The ? in as? is important – if the value is not a double (suppose there was a rogue character in the entry in your file), you will get a nil back. Again, you would need to test for this and handle the error.
Happily, you can do this all in one go:
monsterMaxSpeed = (settings["monsterMaxSpeed"] as? Double) ?? 0.0
(it’s probably the confluence of the two of these issues that’s causing you to get a particularly enigmatic error – the error relates to the other version of Dictionary.subscript which takes an index, not a key, and returns a key/value pair, which isn’t optional, because indices should only address entries that are definitely in the dictionary)

Resources