Swift - Cast Int64 to Anyobject for Nsmutablearray

Swift - Cast Int64 to AnyObject for NSMutableArray

You are using a Foundation array (NSMutableArray), so you should use a Foundation number object:

ma.addObject(NSNumber(longLong:number))

You could also use a native swift array:

var ma = [Int64]()
ma.append(number)

Converting Swift array of [Int64] into NSArray

Map over it:

func foo(tips : [Int64]) {
bar(tips.map { NSNumber(longLong: $0) })
}

This will build a new array, wrapping all Int64 in NSNumber, this new array should be castable to NSArray with no problems.

Swift code problem - trying to cast objects out from a NSMutableArray as a custom object

Better approach would be to use JSONDecoder() instead of a JSONSerailizer. Try using the following code.

struct User: Codable {
var userId, firstName, lastName, userSessionId: String

enum CodingKeys: String, CodingKey {
case userId = "Userid"
case firstName = "First_Name"
case lastName = "Last_Name"
case userSessionId = "Session_ID"
}
}

func parseJSON(_ data: Data) {
do {
let users = try JSONDecoder().decode([User].self, from: data)
users.forEach { user in
print("users first name:", user.firstName)
}
} catch {
print(error.localizedDescription)
}
}

Why is a Swift Array Int compatible with AnyObject?

If you import Foundation (which you must be, because you reference NSCoder) then [Int] is implicitly bridged to NSArray because Int is implicitly bridged to NSNumber. Int64 and your non-objc structs are not implicitly bridged to ObjC types, so arrays of those are not bridged to NSArray.

Why do integers not conform to the AnyObject protocol?

There are two kinds of anything types in Swift – Any, which can truly hold anything – a struct, enum or class, and AnyObject, which can only hold classes.

The reason why it seems like AnyObject can hold structs sometimes is that some specific types are implicitly converted to their NSEquivalent for you as needed, to make Objective-C interop less painful.

When you write let ao: AnyObject = Int(1), it isn’t really putting an Int into an AnyObject. Instead, it’s implicitly converting your Int into an NSNumber, which is a class, and then putting that in.

But only some types have this implicit conversion. Int does, but Int32 doesn’t, hence this behaviour:

// fine
let aoInt: AnyObject = Int(1) as NSNumber
// also fine: implicit conversion
let aoImplicitInt: AnyObject = Int(1)
// not fine: error: 'Int32' is not convertible to 'NSNumber'
let aoInt32: AnyObject = Int32(1) as NSNumber
// but the implicit error is less, ahem, explicit
// error: type 'Int32' does not conform to protocol 'AnyObject'
let aoImplicitInt32: AnyObject = Int32(1)

It could be argued there should be more implicit conversions to grease the wheels, but then again, these implicit conversions are the source of much confusion already and the direction in the latest beta is to have fewer of them rather than more.

How to save an array of Int64 variables using NSCoding in Swift

In the current version of Swift, when you convert [Int] to AnyObject (or AnyObject?), Swift generates NSArray containing NSNumbers. Although NSNumber can contain Int64 (long long int in C/Objective-C), Swift does not convert Int64 to NSNumber automatically, thus, [Int64] cannot be automatically converted to AnyObject.

You can generate an NSArray containing NSNumber explicitly.

let myI64Array = aDecoder.decodeObjectForKey("MyNewArray") as! [NSNumber]
myNewArray = myI64Array.map{$0.longLongValue}

Or:

let myI64Array = myNewArray.map{NSNumber(longLong: $0)}
aCoder.encodeObject(myI64Array, forKey: "MyNewArray")

Is it possible to replicate Swifts automatic numeric value bridging to Foundation (NSNumber) for (U)Int8/16/32/64 types?

Yes (it's possible): by conformance to protocol _ObjectiveCBridgeable

(The following answer is based on using Swift 2.2 and XCode 7.3.)

Just as I was pondering over whether to post or simply skip this question, I stumbled over swift/stdlib/public/core/BridgeObjectiveC.swift in the Swift source code, specifically the protocol _ObjectiveCBridgeable. I've briefly noticed the protocol previously at Swiftdoc.org, but in its current (empty) blueprint form in the latter, I've never given much thought to it. Using the blueprints for _ObjectiveCBridgeable from the Swift source we can, however, swiftly let some native of custom type conform to it.

Before proceeding, note that _ObjectiveCBridgeable is an internal/hidden protocol (_UnderScorePreFixedProtocol), so solutions based on it might break without warning in upcoming Swift versions.


Enabling Int64 bridging to Foundation class NSNumber

As an example, extend Int64 to conform to _ObjectiveCBridgeable, and subsequently test if this quite simple fix is sufficient for the implicit type conversion (bridging) from Int64 to Foundation class NSNumber holds.

import Foundation

extension Int64: _ObjectiveCBridgeable {

public typealias _ObjectiveCType = NSNumber

public static func _isBridgedToObjectiveC() -> Bool {
return true
}

public static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}

public func _bridgeToObjectiveC() -> _ObjectiveCType {
return NSNumber(longLong: self)
}

public static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Int64?) {
result = source.longLongValue
}

public static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Int64?) -> Bool {
self._forceBridgeFromObjectiveC(source, result: &result)
return true
}
}

Test:

/* Test case: scalar */
let fooInt: Int = 42
let fooInt64: Int64 = 42
var fooAnyObj : AnyObject

fooAnyObj = fooInt // OK, natively
fooAnyObj = fooInt64 // OK! _ObjectiveCBridgeable conformance successful

/* Test case: array */
let fooIntArr: [Int] = [42, 23]
let fooInt64Arr: [Int64] = [42, 23]
var fooAnyObjArr : [AnyObject]

fooAnyObjArr = fooIntArr // OK, natively
fooAnyObjArr = fooInt64Arr // OK! _ObjectiveCBridgeable conformance successful

Hence, conformance to _ObjectiveCBridgeable is indeed sufficient to enable automatic by-assignment bridging to the corresponding Foundation class; in this case, NSNumber (in Swift, __NSCFNumber).


Enabling Int8, UInt8, Int16, UInt16, Int32, UInt32, (Int64), and UInt64 bridging to NSNumber

The above conformance of Int64 to _ObjectiveCBridgeable can easily be modified to cover any of the Swift-native integer types, using the NSNumber conversion table below.

/* NSNumber initializer:               NSNumber native Swift type property
-------------------------------- -----------------------------------
init(char: <Int8>) .charValue
init(unsignedChar: <UInt8>) .unsignedCharValue
init(short: <Int16>) .shortValue
init(unsignedShort: <UInt16>) .unsignedShortValue
init(int: <Int32>) .intValue
init(unsignedInt: <UInt32>) .unsignedIntValue
init(longLong: <Int64>) .longLongValue
init(unsignedLongLong: <UInt64>) .unsignedLongLongValue */

Storing Int64 in UserDefaults

A user default object can only be an instance (or a combination of
instances) of
NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.

Some Swift types are automatically bridged to Foundation types,
e.g. Int, UInt, Float, Double and Bool are bridged
to NSNumber. So this could be saved in the user defaults:

var teamsData = Dictionary<String,Dictionary<String,Int>>()

On 64-bit architectures, Int is a 64-bit integer, but on
32-bit architectures, Int is a 32-bit integer.

The fixed-sized integer types such as Int64 are not
automatically bridged to NSNumber. This was also observed
in Swift - Cast Int64 to AnyObject for NSMutableArray.
Therefore, to store 64-bit integers in the user defaults you have
to use NSNumber explicitly:

var teamsData = Dictionary<String,Dictionary<String,NSNumber>>()

// Example how to add a 64-bit value:
let value : UInt64 = 123
teamsData["foo"] = ["bar" : NSNumber(unsignedLongLong: value)]

AnyObject' Doesn't have a Member contactUID Even thought Intelitype Says it Does?

Autocomplete on iOS isn't always accurate, often it will just list all possible selectors / methods.

The root of your problem here is that even though you know HCCContactList holds only HBCDirectoryModel objects, the compiler doesn't as MOContext.executeFetchRequest(freq, error: nil) returns an Array which declares it contains AnyObject's ([AnyObject] / Array<AnyObject>). In order to refer to any of these objects as an HBCDirectoryModel you'll need to conduct a cast to this type.

The easiest way to do this is is to declare your HCCContactList as being an array of HBCDirectoryModel's instead of AnyObject's, and then casting the result of calling MOContext.executeFetchRequest() to this same type.

You can do this as follows

var HCCContactList: Array<HBCDirectoryModel> = []
HCCContactList = MOContext.executeFetchRequest(freq, error: nil) as Array<HBCDirectoryModel>

Or using the shorter syntax

var HCCContactList:[HBCDirectoryModel] = []
HCCContactList = MOContext.executeFetchRequest(freq, error: nil) as [HBCDirectoryModel]


Related Topics



Leave a reply



Submit