46

I was converting from Swift 2 to Swift 3. I noticed that I cannot convert a boolean value to integer value in Swift 3.

let p1 = ("a" == "a") //true

print(true)           //"true\n"
print(p1)             //"true\n"

Int(true)             //1

Int(p1)               //error

For example these syntaxes worked fine in Swift 2. But in Swift 3, print(p1) yields an error.

The error is error: cannot invoke initializer for type 'Int' with an argument list of type '((Bool))'

I understand why the errors are happening. Can anyone explain what is the reason for this safety and how to convert from Bool to Int in Swift 3?

1
  • 1
    For Swift 4, see my accepted answer for a similar question. Commented Jun 8, 2017 at 7:56

10 Answers 10

75

You could use the ternary operator to convert a Bool to Int:

let result = condition ? 1 : 0

result will be 1 if condition is true, 0 is condition is false.

Sign up to request clarification or add additional context in comments.

2 Comments

Ok, so casting from Boolean to Integer value is a no go in swift 3?
I don't believe this conversion was really ever part of Swift. I believe it was a side-effect of implicit conversions through NSNumber. Implicit Bool/Int conversions are an old source of bugs in C (in particular, because non-zero numbers like "2" is "true-ish" but not equal to true). Swift has actively tried to avoid these historic sources of bugs.
68

Swift 5

Bool -> Int

extension Bool {
    var intValue: Int {
        return self ? 1 : 0
    }
}

Int -> Bool

extension Int {
    var boolValue: Bool {
        return self != 0 
    }
}

4 Comments

Beat me to it! This is definitely my preferred solution. It adheres to Swift conventions more than other solutions here.
And to go in the opposite direction (Int -> Bool) stackoverflow.com/a/45008003/1382210
Never thought to solve it this way. This is quite good. Works like NSNumber.
Amazing mate. You have just saved me some time and head-scratching :)
21

Try this,

let p1 = ("a" == "a") //true
print(true)           //"true\n"
print(p1)             //"true\n"

Int(true)             //1

Int(NSNumber(value:p1)) //1

1 Comment

Seems deprecated
13

EDIT - From conversations in the comments, it is becoming clearer that the second way of doing this below (Int.init overload) is more in the style of where Swift is headed.

Alternatively, if this were something you were doing a lot of in your app, you could create a protocol and extend each type you need to convert to Int with it.

extension Bool: IntValue {
    func intValue() -> Int {
        if self {
            return 1
        }
        return 0
    }
}

protocol IntValue {
    func intValue() -> Int
}

print("\(true.intValue())") //prints "1"

EDIT- To cover an example of the case mentioned by Rob Napier in the comments below, one could do something like this:

extension Int {
    init(_ bool:Bool) {
        self = bool ? 1 : 0
    }
}

let myBool = true
print("Integer value of \(myBool) is \(Int(myBool)).")

6 Comments

Or combine @eric-aya 's ternary op recommendation with a protocol for maximum conciseness!
This approach has generally been discouraged by the core Swift team. They recommend Int.init overloads rather than methods to perform full-width conversions.
Any documentation I could read to that effect @Rob-napier? I'd like to know more about why it's discouraged and the discussion leading to that decision.
I can't put my hands on a conversation right now; buried somewhere in swift-evo. But you can see the results of the opinion by watching how stdlib has evolved. For example, see github.com/apple/swift-evolution/blob/master/proposals/… and note where ...value methods have been converted to init (there were never many ...value methods in stdlib, but see ObjectIdentifier and StaticString). Note also in the Swift 3 style guidelines that type conversions are only discussed in terms of init's. Never methods.
Cool, more curious than anything. Thanks!
|
6

Swift 5.4

This is a more generic approach which is applicable for other types than just Int.

extension ExpressibleByIntegerLiteral {
    init(_ booleanLiteral: BooleanLiteralType) {
        self = booleanLiteral ? 1 : 0
    }
}

let bool1 = true
let bool2 = false

let myInt = Int(bool1) // 1
let myFloat = Float(bool1) // 1
let myDouble = Double(bool2) // 0
let myCGFloat = CGFloat(bool2) // 0

Comments

2

unsafeBitCast is always an option

let int: Int = Int(unsafeBitCast(someBool, to: UInt8.self))

2 Comments

Offering an explanation is always useful on Stack Overflow, but it's especially important where the question has been resolved to the satisfaction of the community. Help readers out by explaining what your answer does different and when it might be preferred. Can you edit your question to add more detail?
That doesn't seem safe
0

You could use hashValue property:

let active = true
active.hashValue // returns 1
active = false
active.hashValue // returns 0

2 Comments

If you do this in Swift 4.2, you are going to get values like 482808648934333090 and similar.
Yes, you can look at this Q&A stackoverflow.com/q/52116428/4711785
0

Tested in swift 3.2 and swift 4

There is not need to convert it into Int

Try this -

let p1 = ("a" == "a") //true

print(true)           //"true\n"
print(p1)             //"true\n"

Int(true)             //1

print(NSNumber(value: p1))   

Comments

0

In swift 5:

you can do this:

let x = ("a" == "a")

Int(truncating: x as NSNumber)

Comments

0

This is my preferred adaptation of existing solutions, just an overload of Int. This way I don't have to remember any additional syntax.

func Int(_ boolean: Bool) -> Int {
    boolean ? 1 : 0
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.