4

In Tests project I've got extensions with some test helper functions. Like this:

extension Employee {
    static func mockDict() -> Dictionary<String, Any>! {
        return ["ID": arc4random() % 1000,
                "FirstName": "Employee First Name",
                ...]
    }
}

(I've stripped unnecessary code). I've got problem accessing ID from this dictionary for some yet unknown reason. I've got SIGABRT 6 when casting

employeeDict["ID"] as! Int

Xcode debugger console also don't like this particular integer:

Ints

Strings work fine. Have you encountered such problem? Any ideas?

EDIT: Just in case anyone will encounter this problem too. CASTING FROM UInt32/Int32 TO Int FAILS BY DESIGN. Even if object was casted into Any or Anyobject inbetween. Even though

@available(*, message: "Converting UInt32 to Int will always succeed.")
public init?(exactly value: UInt32)

in Int's declaration

public struct Int : SignedInteger, Comparable, Equatable {
    ...
}

and

public struct Int32 : SignedInteger, Comparable, Equatable {
    ...
}

EDIT 2 for those who might encounter this behaviour in JSON serialization. Yes, serialization fails with error NSInvalidArgumentException Invalid type in JSON write (_SwiftValue) if asked to serialize UInt32, Int64 or any Integer protocol instance other than Int

3 Answers 3

9

Try this:

let a = employeeDict["ID"] as! UInt32
let number = Int(a)

Now you can use number to perform any action.

3
  • 1
    Thank you, I've made workaround like this. But I'm still baffled, because app is running on iPhone 7 sim where Int is 64 bit. Also 892 is definitely an Integer that won't cause overflow or any other problems. Commented Oct 25, 2016 at 1:03
  • I think the problem is because you are trying to cast the number as an Integer instead of creating an integer out of the UInt32. Also, if my answer helped you, could you please accept it? Thanks! Commented Oct 25, 2016 at 1:19
  • 1
    Done. I've added some details into the question. BTW, only universal way I found is to use NSNumber in order to add ability to cast Integer protocol instances into Int without crashing. Commented Oct 25, 2016 at 4:43
2

This works for me:

Int("\(employeeDict["ID"]!)")
1
  • Yes, you can go with intermediate casting to overcome this. The problem of UInt32 -> Int conversion was mostly fixed, most notably in JSONSerialization which was crashing serializing dicts with UInt32 Commented Aug 8, 2019 at 16:10
1

Swift "primitive" numeric types are not interchangeable and cannot be cast to each other.

You need to use an initializer.

Since arcRandom() returns UInt32 and you want to use the value as Int, convert it right away in the dictionary declaration:

["ID": Int(arc4random() % 1000), ...

PS: Do not declare a clearly non-optional as implicit unwrapped optional return value, that defeats the strong type system of Swift.

static func mockDict() -> Dictionary<String, Any>
2
  • First I encounter this problem in JSONSerialization. After digging deeper I found problem that I listed in the question. There is no easy solution for casting of non-Int integers to Int if they were casted into Any first. Say, for instance, we have a Swift DB adapter with integer fields of different size. In Objective C they could be translated into objects and then to integers of any kind or serialized. So I was baffled with lack of this functionality in Swift. Commented Oct 25, 2016 at 22:35
  • Regarding "!" it's possible for test logic to have nil result, I've just stripped away code for generating possible dicts. So you are right on that, but it's OK in actual code. Commented Oct 25, 2016 at 22:35

Not the answer you're looking for? Browse other questions tagged or ask your own question.