struct S {}
let s1 = S()
//I thought this would throw a compilation error
//because struct doesn't conform to AnyObject
let a : AnyObject = s1 as AnyObject
Question
Why does the above code compile without errors?
Am I missing something?
Based on the documentation:
AnyObject can be used as the concrete type for an instance of any class, class type, or class-only protocol.
Ugh, this is one of my gripes with Swift. It's an Objective C interop feature, which although useful, is too implicit/mysterious. This implicit boxing behaviour only happens when Foundation is imported, and only on systems with ObjC support (Apple's platforms).
Some Swift types bridge to specific ObjC counterparts, like NSString, NSNumber, NSArray, NSDictionary, etc. All other swift value types (like structs and tuples) are capable of being wrapped in a private ObjC class called _NSSwiftValue, which makes it possible to hand them off to ObjC APIs.
The most confusing thing is that the object has an ill-defined identity (object address) as far as Objective C is concerned, and if your type doesn't conform to Hashable, then the Hash value of the object is also ill-defined, which can lead to all kinds of hard-to-nail-down bugs.
Just my observation, it doesn't tell why it is happening but looks like all free bridging will satisfy is clause
struct S {}
let s1 = S()
print(s1 is AnyObject) //compiler: 'is' test is always true
import Foundation
let str : String = ""
print(str is NSString) //compiler: 'is' test is always true
Question:
So is there a way to be sure only class instances can be passed to a function (Example below)?
func f1(anyObject: AnyObject) {} //Is there any way to restrict the parameter to only class instances?
let a : AnyObject = S() as AnyObject //S is a struct
f1(anyObject: a) //valid
You can restrict that arguments are objects, but you can't restrict that they are values. The best you have for that is something like my CastError. Which is not good enough!
This implements the Objective-C class that is used to carry Swift values
that have been bridged to Objective-C objects without special handling.
The class is opaque to user code, but is NSObject- and NSCopying-
conforming and is understood by the Swift runtime for dynamic casting
back to the contained type.
So I suppose the reason to do it is only to pass it to Objective-C. It is like an NSObject with a type erasure (to erase NSObject type)