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 NSNumber
s. 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
Add Animations to Foreach Loop Elements (Swiftui)
Draw a Hole in a Rectangle with Spritekit
Contextual Type for Closure Argument List Expects 1 Argument, But 4 Were Specified
How to Make the Memberwise Initialiser Public, by Default, for Structs in Swift
Swift, How to Play Sound When Press a Button
Dynamically Change Text of Realitykit Entity
Swift: How to Call Cckeyderivationpbkdf from Swift
Swift - Seeding Arc4Random_Uniform? or Alternative
Swiftui Foreach Based on State Int
Get Image from Calayer or Nsview (Swift 3)
Set the Size and Position of All Windows on the Screen in Swift
Why Can't We Use Protocol 'Encodable' as a Type in the Func
How to Handle Closure Recursivity
Swift Error: Missing Return in a Function Expected to Return 'String'
Differencebetween Swift 2.0 Do-Try-Catch and Regular Java/C#/C++ Exceptions