19

In Swift3, I previously converted a Bool to an Int using the following method

let _ = Int(NSNumber(value: false))

After converting to Swift4, I'm getting a "'init' is deprecated" warning. How else should this be done?

D. Cohen
  • 567
  • 1
  • 7
  • 22

2 Answers2

28

With Swift 4.2 and Swift 5, you can choose one of the 5 following solutions in order to solve your problem.


#1. Using NSNumber's intValue property

import Foundation

let integer = NSNumber(value: false).intValue
print(integer) // prints 0

#2. Using type casting

import Foundation

let integer = NSNumber(value: false) as? Int
print(String(describing: integer)) // prints Optional(0)

#3. Using Int's init(exactly:) initializer

import Foundation

let integer = Int(exactly: NSNumber(value: false))
print(String(describing: integer)) // prints Optional(0)

As an alternative to the previous code, you can use the more concise code below.

import Foundation

let integer = Int(exactly: false)
print(String(describing: integer)) // prints Optional(0)

#4. Using Int's init(truncating:) initializer

import Foundation

let integer = Int(truncating: false)
print(integer) // prints 0

#5. Using control flow

Note that the following sample codes do not require to import Foundation.

Usage #1 (if statement):

let integer: Int
let bool = false

if bool {
    integer = 1
} else {
    integer = 0
}
print(integer) // prints 0

Usage #2 (ternary operator):

let integer = false ? 1 : 0
print(integer) // prints 0
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
5

You can use NSNumber property intValue:

let x = NSNumber(value: false).intValue

You can also use init?(exactly number: NSNumber) initializer:

let y = Int(exactly: NSNumber(value: false))

or as mentioned in comments by @Hamish the numeric initializer has been renamed to init(truncating:)

let z = Int(truncating: NSNumber(value: false))

or let Xcode implicitly create a NSNumber from it as mentioned by @MartinR

let z = Int(truncating: false)

Another option you have is to extend protocol BinaryInteger (Swift 4) or Integer (Swift3) and create your own non fallible initializer that takes a Bool as parameter and returns the original type using the ternary operator as suggested in comments by @vadian:

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

let a = Int(true)   // 1
let b = Int(false)  // 0

let c = UInt8(true)  // 1
let d = UInt8(false) // 0
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • Great, it works! Is there a reason why the previous method is deprecated? – D. Cohen Jun 07 '17 at 19:28
  • In Swift 4 even `let x = Int(exactly: false)!` works – vadian Jun 07 '17 at 19:37
  • 5
    The `init(_:)` initialisers to convert from `NSNumber` to Swift numeric types were renamed to `init(truncating:)` as per [SE-0170](https://github.com/apple/swift-evolution/blob/master/proposals/0170-nsnumber_bridge.md) – so `Int(truncating: NSNumber(value: false))`. But `.intValue` should achieve the same result in this case (although of course as vadian points out, there's no need to go via `NSNumber` for this in the first place). – Hamish Jun 07 '17 at 19:39
  • 2
    @vadian: `let x = Int(exactly: false)` implicitly creates a `NSNumber` from the boolean. – Martin R Jun 07 '17 at 19:43
  • ... and wouldn't compile without importing Foundation. – Martin R Jun 07 '17 at 19:49