Any[Object]

You use Swift AnyObject wrong.

So you probably read The Swift Programming Language book, where this piece can be found:

Swift provides two special types for working with nonspecific types:

  • Any can represent an instance of any type at all, including function types.
  • AnyObject can represent an instance of any class type.

Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to specify the types you expect to work with in your code.

However, this paragraph isn't accurate. Some may say it's misleading. A little more accurate is a documentation:

You use AnyObject when you need the flexibility of an untyped object or when you use bridged Objective-C methods and properties that return an untyped result. AnyObject can be used as the concrete type for an instance of any class, class type, or class-only protocol.

I emphasized the part that is actually correct and makes the AnyObject distinct from Any.

Maybe you read about Class Only Protocols In Swift 4 and learned, that it's preferable now to use AnyObject rather than class keyword:

Since Swift 4 the preferred way to declare a class-only protocol is to use AnyObject rather than class

It's unfortunate because AnyObject is more than just a class. Actually, AnyObject may be a class type and the value type as well.

Array<AnyObject>

let array:[AnyObject] = []

if array is [Int] {
    // yes [AnyObject] is [Int]
}

if array is [String] {
    // yes [AnyObject] is [String]
}

not what I expected. Array<Element> and Int is a value type, struct:

public struct Int : FixedWidthInteger, SignedInteger { }
public struct Array<Element> { }

definitely not a class 😳 But it's an array so who knows.

Value AnyObject

Now. The book taught me that AnyObject could represent an instance of any class type. So... what if I build a generic class where the value type supposes to be an object rather than value type. I should use AnyObject, so I defined Container class:

class Container<T> where T: AnyObject {
    init(value: T) {
        print("Initialize with object \(value)")
    }
}

my container has a value, for this exercise let's define a Dog as one possible value and instantiate the dog named "Rex":

class Dog {
    let name: String
    init(name: String) {
        self.name = name
    }
}

let rex = Dog(name: "Rex")

Cats are different. Let's define a Cat as a struct. This cat is named "Bella":

struct Cat {
    let name: String
}

let bella = Cat(name: "Bella")

Quiz

  • rex variable is a class/value type? [1]
  • bella variable is class/value type? [2]

3o6gDWvntdm16XezUA

You're correct! The rex variable is an object (class Dog), so it is an AnyObject. Easy to check:

if rex is AnyObject { // warning: 'is' test is always true
    print("\(rex) is AnyObject")
}

You're correct! The bella variable is a value type (struct Cat), so it is an AnyObject. Easy to check:

if bella is AnyObject {
    print("\(bella) is AnyObject")
}

Wait WAT?

As pointed earlier, bella variable is a struct hence it's a value type. AnyObject that can represent an instance of any class type. Nobody said it could represent the value type as well.

Isn't that why we have Any type to represent both already?

Kc7DXpUjFWAzm

Some may say: it will crash at runtime. However, it won't.

let container = Container(value: bella as AnyObject)

container instance is of type Container<Swift.AnyObject>. So what? I just put a value where an object is expected. Why? Because I can.

What can possibly go wrong?

Possible consequences of use AnyObject is API misuse: pass the value where Object is expected.

Rules

The rules for proper use of AnyObject right would be:

  • Don't use AnyObject as a generics constraint.
  • Don't use is AnyObject nor as? AnyObject to check if a variable is a class type.
  • Don't use AnyObject.
  • Use class for a class-only protocol.
  • Use Any.

  1. an instance of a class ↩︎

  2. a value (struct) ↩︎