Why Do Integers Not Conform to the Anyobject Protocol

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.

Type 'OSType' does not conform to protocol 'AnyObject' in Swift 2.0

This is the kCVPixelFormatType_32BGRA definition in Swift 1.2:

var kCVPixelFormatType_32BGRA: Int { get } /* 32 bit BGRA */

This is its definition in Swift 2.0:

var kCVPixelFormatType_32BGRA: OSType { get } /* 32 bit BGRA */

Actually the OSType is a UInt32 which can't implicit convert to a NSNumber:

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.

https://stackoverflow.com/a/28920350/907422

So try this:

videoDataOutput?.videoSettings = [kCVPixelBufferPixelFormatTypeKey: Int(kCVPixelFormatType_32BGRA)]

or

videoDataOutput?.videoSettings = [kCVPixelBufferPixelFormatTypeKey: NSNumber(unsignedInt: kCVPixelFormatType_32BGRA)

Is Float, Double, Int an AnyObject?

Because you have Foundation imported, Int, Double, and Float get converted to NSNumber when passed to a function taking an AnyObject. Type String gets converted to NSString. This is done to make life easier when calling Cocoa and Cocoa Touch based interfaces. If you remove import UIKit (or import Cocoa for OS X), you will see:

error: argument type 'Int' does not conform to expected type 'AnyObject'

when you call

passAnyObject(a)

This implicit conversion of value types to objects is described here.


Update for Swift 3 (Xcode 8 beta 6):

Passing an Int, Double, String, or Bool to a parameter of type AnyObject now results in an error such as Argument of type 'Int' does not conform to expected type 'AnyObject'.

With Swift 3, implicit type conversion has been removed. It is now necessary to cast Int, Double, String and Bool with as AnyObject in order to pass it to a parameter of type AnyObject:

let a = 1
passAnyObject(a as AnyObject)

When is a variable a AnyObject but not a NSObject

On platforms with Objective-C compatibility (which means all of Apple's platforms and no others), every class type is (secretly) a subclass of the SwiftObject class, which provides NSObject protocol conformance.

On other platforms, NSObject is “just another class”, implemented in Swift, so only a class that explicitly has NSObject as a superclass has instances that are NSObjects.

Swift issue: About Type Casting for AnyObject

This is a little confusing because of the bridging that Swift does to Objective-C, where most things are classes and there are fewer value-types. To see what Swift does without the bridge, create a new playground and delete the import ... statement at the top, then try casting an Int to Any (no problem) and AnyObject:

let num = 23                               // 23
let anyNum: Any = num // 23
let anyObjectNum: AnyObject = num
// error: type 'Int' does not conform to protocol 'AnyObject'

Now add import Foundation at the top of your playground:

import Foundation

let num = 23 // 23
let anyNum: Any = num // 23
let anyObjectNum: AnyObject = num // 23

The error goes away - why? When it sees the attempt to cast an Int to AnyObject, Swift first bridges num to be an instance of the Objective-C NSNumber class, found in Foundation, then casts it to the desired AnyObject. The same thing is happening in your array.

You can more or less prove this is the case using the is keyword - since NSNumber bridges to all the numeric types in Swift, it returns true in some funny cases:

anyNum is Int                              // true
anyNum is Double // false
anyObjectNum is Int // true
anyObjectNum is UInt // true
anyObjectNum is Double // true
anyObjectNum is Float // true

Argument type 'Int' does not conform to expected type 'NSCoding & NSCopying & NSObjectProtocol'

As ORKTextChoice's initialiser has an abstract parameter type for value:, Swift will fallback on interpreting the integer literals passed to it as Int – which does not conform to NSCoding, NSCopying or NSObjectProtocol. It's Objective-C counterpart, NSNumber, however does.

Although, rather than casting to NSCoding & NSCopying & NSObjectProtocol, which would result in a bridge to NSNumber (albeit an indirect and unclear one), you can simply make this bridge directly:

let textChoices = [
ORKTextChoice(text: "Create a ResearchKit app", value: 0 as NSNumber),
ORKTextChoice(text: "Seek the Holy grail", value: 1 as NSNumber),
ORKTextChoice(text: "Find a shrubbery", value: 2 as NSNumber)
]

Your original code would have worked prior to Swift 3, as Swift types were able to be implicitly bridged to their Objective-C counterparts. However, as per SE-0072: Fully eliminate implicit bridging conversions from Swift, this is no longer the case. You need to make the bridge explicit with as.

((Any) throws - Bool) throws - Optional Any ') cannot conform to 'BinaryInteger'

With help from @Rob in the comments, I was able to unwrap the message properly and remove unnecessary guard let statements to run my delegate function. Below is the updated piece of code.

  1. Changed message.values.first? as Int as the rate was in an integer format.
  2. Removed guard let statements in converting the heartRate into the double format, as it was non-optional.
extension WatchKitConnection: WCSessionDelegate {

func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
print("didReceiveMessage from watch")
print(message)

// delegate?.updateLatestHeartRate(Double(message.values.first))

guard let heartRate = message.values.first as? Int else {
return
}

let heartRateDouble = Double(heartRate)

print("printing heartRate double from message\(heartRateDouble)")

delegate?.updateLatestHeartRate(heartRateDouble)

print("updateLatestHeartRate")

}
}


Related Topics



Leave a reply



Submit