Get the Type of Anyobject Dynamically in Swift

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



Leave a reply



Submit