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

user1232690
  • 481
  • 5
  • 16

3 Answers3

9

Try this:

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

Now you can use number to perform any action.

Pranav Wadhwa
  • 7,666
  • 6
  • 39
  • 61
  • 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. – user1232690 Oct 25 '16 at 01: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! – Pranav Wadhwa Oct 25 '16 at 01: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. – user1232690 Oct 25 '16 at 04:43
2

This works for me:

Int("\(employeeDict["ID"]!)")
Oz Shabat
  • 1,434
  • 17
  • 16
  • 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 – user1232690 Aug 08 '19 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>
vadian
  • 274,689
  • 30
  • 353
  • 361
  • 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. – user1232690 Oct 25 '16 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. – user1232690 Oct 25 '16 at 22:35