Get the type of AnyObject dynamically in Swift
Typically this is what generics are for. There is seldom good reason for having an AnyObject
in code that doesn't interact with ObjC. If you're then performing different actions based on the type, then you probably actually meant to use overloading.
That said, there are several ways to get access to the type. Typically you want to run different code depending on the type, so you can use a switch
for that:
let x:AnyObject = "asdf"
switch x {
case is String: println("I'm a string")
default: println("I'm not a string")
}
or
let x:AnyObject = "asdf"
switch x {
case let xString as String: println("I'm a string: \(xString)")
default: println("I'm not a string")
}
Or you can use an if:
if let string = x as? String {
println("I'm a string: \(string)")
}
See "Type Casting for Any and AnyObject" in the Swift Programming Language for more discussion.
But again, unless you're working with ObjC code, there is seldom reason to use Any
or AnyObject
. Generics and overloads are the tools designed to solve those problems in Swift.
How do you find out the type of an object (in Swift)?
Swift 3 version:
type(of: yourObject)
How to cast from AnyObject to the dynamic type?
You could use a protocol
protocol Respondable {
var response : NSDictionary {get}
}
and then constrain the type of objectOrNil
to that protocol
someObject.callService(classObject, withCompletionBlock: {(objectOrNil : [Respondable]!, errorOrNil:NSError?) -> Void
How to check whether an object is kind of a dynamic class type in swift?
Personally, I think @JeremyP's suggestion to use Mirror
is the best; though I would make a couple of tweaks to it:
/// Conditionally cast `x` to a given dynamic metatype value, taking into consideration
/// class inheritance hierarchies.
func conditionallyCast<T, U>(_ x: T, to destType: U.Type) -> U? {
if type(of: x) is AnyClass && destType is AnyClass { // class-to-class
let isCastable = sequence(
first: Mirror(reflecting: x), next: { $0.superclassMirror }
)
.contains { $0.subjectType == destType }
return isCastable ? (x as! U) : nil
}
// otherwise fall back to as?
return x as? U
}
Here we're using sequence(first:next:)
to create a sequence of metatypes from the dynamic type of x
through any superclass metatypes it might have (probably the first use of the function I've seen that doesn't look awful :P). In addition, we're falling back to doing an as?
cast when we know we're not doing a class-to-class cast, which allows the function to also work with protocol metatypes.
Then you can simply say:
extension Sequence {
func ofType<T>(_ metatype: T.Type) -> [T] {
return flatMap { conditionallyCast($0, to: metatype) }
}
}
protocol P {}
class Animal {}
class Mammal: Animal {}
class Monkey: Mammal, P {}
class Pig: Mammal {}
class Human: Mammal, P {}
let animals = [Monkey(), Pig(), Human(), Mammal(), Animal()]
let animalType: Animal.Type = Mammal.self
print(animals.ofType(animalType)) // [Monkey, Pig, Human, Mammal]
print(animals.ofType(P.self)) // [Monkey, Human]
Another option, assuming you're on an Apple platform (i.e have access to the Objective-C runtime), is to use the the Objective-C metaclass method isSubclass(of:)
in order to check if a given metatype is equal, or is a subclass of another:
import Foundation
/// Conditionally cast `x` to a given dynamic metatype value, taking into consideration
/// class inheritance hierarchies.
func conditionallyCast<T, U>(_ x: T, to destType: U.Type) -> U? {
let sourceType = type(of: x)
if let sourceType = sourceType as? AnyClass,
let destType = destType as? AnyClass { // class-to-class
return sourceType.isSubclass(of: destType) ? (x as! U) : nil
}
// otherwise fall back to as?
return x as? U
}
This works because on Apple platforms, Swift classes are built on top of Obj-C classes – and therefore the metatype of a Swift class is an Obj-C metaclass object.
How can I find the type of a property dynamically in swift (Reflection/Mirror)?
You don't need to inherit from NSObject
(unless you have a good reason to).
class Employee {
var id: String?
var someArray: [Employee]?
}
let employee = Employee()
for property in Mirror(reflecting: employee).children {
print("name: \(property.label) type: \(type(of: property.value))")
}
Output
name: Optional("id") type: Optional<String>
name: Optional("someArray") type: Optional<Array<Employee>>
This also works with Structs
How to test whether generic variable is of type AnyObject
In Swift 3, everything is bridgeable to AnyObject
due to the introduction of _SwiftValue
(see this Q&A for more info), that can wrap anything that isn't directly bridgeable to Objective-C in an opaque Objective-C compatible box.
Therefore is AnyObject
will always be true, as anything can be represented as an AnyObject
via wrapping in a _SwiftValue
.
One way to check whether a value is a reference type (as shown in this Q&A) is to type-check the type of the value against the metatype of AnyObject
, AnyClass
(aka AnyObject.Type
).
For generics, if you want to check whether the static type of T
is a reference type, you can do:
isObject = T.self is AnyClass
If you want to check whether the dynamic type of a value typed as T
is a reference type (such as val
in your example), you can use the type(of:)
function on the unwrapped value, as the aforementioned Q&A suggests:
if let val = val {
isObject = type(of: val) is AnyClass
// ...
}
The difference between these two approaches is that when T
is of type Any
(or a non AnyObject
abstract type), T.self is AnyClass
will return false
(which could be useful if you want a box where the value could be a reference or value type) – type(of: val) is AnyClass
however, will return whether val
itself is a reference type.
Swift Check Dynamic Type of Array of Objects
You can keep Any
instances and compare for Any.Type
types with the ==
operator. Example based on the code in @lassej answer:
let array: [Any] = [UIView(), "hellow", 12, true]
let types: [(Any.Type, String)] = [
(UIView.self, "UIView"),
(String.self, "String"),
(Int.self, "Integer")
]
anyLoop: for any in array {
for (type, name) in types {
if any.dynamicType == type {
print( "type: \(name)")
continue anyLoop
}
}
print( "unknown type: \(any.dynamicType)")
}
// Prints:
// type: UIView
// type: String
// type: Integer
// unknown type: Bool
AnyObject not working in Xcode8 beta6?
The warning works as intended: the false
return of TestStruct() is AnyObject
, however, does not
The prior version of this answer perceived the warning,
'is' test is always true
as the bug, and contained some discussion as to why this perceived buggy warning would manifest itself. That TestStruct() is AnyObject
evaluated to false
at runtime, however, was perceived as expected behaviour.
Given the comments to the bug report filed by the OP (SR-2420), it seems the situation is the reverse: since Xcode 8/beta 6, the is
test should always evaluate to true
, and the bug the OP:s post is the fact that TestStruct() is AnyObject
evaluates to false
during runtime.
Joe Groff writes:
This is correct, because everything bridges to
AnyObject
now....
is
/as
AnyObject
always succeed for all types now. It's behaving
as intended.
The new SwiftValue
box for conversion from Swift values to Obj-C objects
(for additional details, see discussion in the comments below, thanks @MartinR)
It seems as if Swift values that are not explicitly implemented to be bridgeable to Obj-C objects via e.g. conformance to _ObjectiveCBridgeable
(see e.g. the following Q&A for details regarding _ObjectiveCBridgeable
), will instead automatically make use of the new SwiftValue
box to allow conversion to Obj-C objects.
The initial commit message for swift/stdlib/public/runtime/SwiftValue.mm reads:
Runtime: Implement an opaque 'SwiftValue' ObjC class to hold bridged values
If there's no better mapping for a Swift value into an Objective-C
object for bridging purposes, we can fall back to boxing the value in
a class. This class doesn't have any public interface beyond being
NSObject
-conforming in Objective-C, but is recognized by the Swift
runtime so that it can be dynamically cast back to the boxed type.
Related Topics
Changing Tab Bar Color (Swift)
What Does "Arg = Exploded" Mean in Swift Crash Log
Using @Discardableresult for Closures in Swift
Set Custom Uiview Frame in Uiviewrepresentable Swiftui
Checking Conforms Protocol with Associatedtype in Swift
Why Use Class Only Protocols in Swift
Cast Cgfloat to Int in Extension Binaryfloatingpoint
Ar with iOS: Putting a Light in the Scene Makes Everything Black
How to Pass a Class and Method to Create an Instance of a Class
How to Test Required Init(Coder:)
Explit Conformance to Codable Removes Memberwise Initializer Generation on Structs
Xcodebuild -Exportarchive Wont Allow Me to Specify Filename
How to Cast [Int8] to [Uint8] in Swift
Swiftui Onmovecommand Actions Aren't Executed