DavideBombacigno
DavideBombacigno

Reputation: 21

Convert String to int in Swift 3

I have the following variable:

 var npill : String!

It's an Int value, but I can't set it as Int because of:

npillIn: fieldNumeroPillole.text!,

How can I convert this var to a Int var? I have tried the following:

var number1: Int = (npill! as NSString).intValue

By the above code I receive the following error:

cannot use instance member 'npill' within property initializer, property initializers run before "self" is aviable

If I then set:

var number1: Int = (self.npill! as NSString).intValue

The error it outputs is as follows:

Value of type '(NSObject) -> () -> Farmaco' has no member 'npill'

If anyone knows how I should be converting it properly, please let me know.

Upvotes: 1

Views: 9050

Answers (2)

dfrib
dfrib

Reputation: 73166

(As @Hamish pointed out in a comment below, I misunderstood what the OP was really asking about. I'll leave my answer, however, as some curiosa and insights regarding ! type annotation, which may be relevant for future readers of this question)


For any type of String optionals, their values needs to be unwrapped prior to using the failable init?(_ text: String) initializer or Int.

In your example, the variable npill is an optional, as you've annotated its type with the ! specifier (which should be used with care). Quoting from the implemented evolution proposal SE-0054 [emphasis mine]

Appending ! to the type of a Swift declaration will give it optional type and annotate the declaration with an attribute stating that it may be implicitly unwrapped when used.

Hence, it's entirely legal to use npill directly with the init?(_ text: String) initializer of Int, as it will be unwrapped (without any safety check for nil content!) on-the-fly upon use.

// UNSAFE example!
var npill: String! = "42"
if let npillInt = Int(npill) {
    /* ^^^^^^^^       ^^^^^- since 'npill' has a type annotated with
           |                 '!', it will be unsafely unwrapped at
           |                 this point                             
           \
          the optional binding here safely unwraps the return from
          the failable Int initializer, but has nothing to do with
          the unwrapping of 'npill'                                 */
    print(npillInt) // 42
}

// why unsafe? consider
npill = nil

if let npillInt = Int(npill) { // runtime exception!
    // ...
}

Generally you should avoid using the ! annotation, however, unless you are entirely certain that the content of the resulting optional variable will never ever be nil.

Leaving aside the cons of even using the ! annotation: you may implement a safe version of the unsafe example above, by overriding the unsafe implicit unwrapping with safe explicit unwrapping techniques. For a given optional variable declared using the ! annotation, we may still apply safe means to unwrap it, e.g. optional binding or using the nil coalescing operator. @appzYourLife has already showed one perfectly valid and safe way to handle the unwrapping and attempted type conversion of npill using optional binding, so I'll simply include another example using the nil coalescing operator instead:

// "safe" example (STILL: why use the `!` annotation?)
var npill: String! = "42"
if let npillInt = Int(npill ?? "x") {
                /*    ^^^^^ if 'npill' is 'nil', the Int initializer will
                            be given the value "x", which itself will lead 
                            it to fail, which is safe here as we intend to
                            bind the result of the initialization to 'npillInt' */
    print(npillInt) // 42
}

npill = nil
if let npillInt = Int(npill ?? "x") {
    // ... doesnt enter
}

The consensus of the examples above is that if we're even slightly uncertain whether npill can ever be nil or not, we need to treat it as if it was just an optional not type annotated with ! (i.e. String?); overriding the default unsafe unwrapping with safe means when working with the variable. In such a case, why would we even want to use the ! typ annotation at all, as it only brings fragility/danger to our application?

Upvotes: 0

Luca Angeletti
Luca Angeletti

Reputation: 59496

Update

Thank you to @Hamish for pointing out what the OP was asking

So the problem seems to be this

import Foundation

class Foo {
    var npill : String!
    var number1: Int = (npill! as NSString).intValue
}

error: cannot use instance member 'npill' within property initializer; property initializers run before 'self' is available
var number1: Int = (npill! as NSString).intValue
                    ^

What's going on here?

You are using a property to populate another property, and this is not allowed.

Solution

However you can easily fix the problem postponing the initialisation of number1. Infact if you make number1 lazy, it will be populated only when used.

class Foo {
    var npill : String!
    lazy var number1: Int = { return Int(self.npill!)! }()
}

Warning: Of course this code will crash if npill is still nil when number1 is used.

Old version

You can simply write

let npill: String! = "34"
if let npill = npill, let num = Int(npill) {
    print(num) // <-- here you have your Int
}

Upvotes: 2

Related Questions