Any vs AnyObject vs any in Swift


Greetings, traveler!

Some tools in the Swift language have pretty similar names. I am talking about Any, AnyObject, and any. In this article, we will consider the differences between them.

Any

Any in Swift is a type that can represent any object, including instances of function types.

let array: [Any] = [
    "Jack",
    55,
    { () -> Void in },
    (44.9, 0)
]

Therefore, it is not a good idea to use Any frequently. You must always cast objects, erasing the Swift language’s great feature — type safety. I recommend using something else instead of Any; for example, you can use protocols. Consider this code.

struct StringValidator {
    func validate(_ value: Any) -> Bool {
        guard let string = value as? String else {
            fatalError("This validator accepts only strings")
        }

        return !string.isEmpty
    }
}

We can easily make it more maintainable and safer with protocols.

protocol ValidatorProtocol {
    associatedtype Value
    
    func validate(_ value: Value) -> Bool
}

struct StringValidator: ValidatorProtocol {
    
    typealias Value = String
    
    func validate(_ value: Value) -> Bool {
        value.isEmpty
    }
    
}

struct IntValidator: ValidatorProtocol {
    
    typealias Value = Int
    
    func validate(_ value: Int) -> Bool {
        value > .zero
    }
    
}

If you want to maintain the same level of versatility as using Any, you can use generics instead.

struct Validator<T>: ValidatorProtocol {
    
    typealias Value = T
    
    func validate(_ value: Value) -> Bool {
        if let string = value as? String {
            return !string.isEmpty
        } else if let int = value as? Int {
            return int > .zero
        }
        
        return false
    }
    
}

AnyObject

Only classes and actors conform to AnyObject in Swift, allowing you to restrict protocols to reference types only. Consider this example.

actor Actor {}

func perform(_ value: AnyObject) {

}

let actor = Actor()
perform(actor)

You can also use AnyObject with your custom protocols, restricting its use with value types.

actor Actor {}

class Class {}

struct Struct {}

protocol CustomProtocol: AnyObject {
    func doSmth()
}

extension Class: CustomProtocol {
    func doSmth() {}
}

extension Struct: CustomProtocol { // ❌ Non-class type 'Struct' cannot conform to class protocol 'CustomProtocol'
    func doSmth() {}
}

Note: When using actors, you can mark this function with the nonisolated keyword.

extension Actor: CustomProtocol {
    nonisolated func doSmth() {}
}

Do you want to read more about actors? I have an article about them and an article about the nonisolated and the isolated keywords.

Moreover, you can find the crash course on Swift Concurrency here. It’s free, by the way!

any

SE-0335 introduces a new any keyword to mark existential types in Swift. You can use it with generic protocols. Let’s take a look at this example.

protocol AppleDevice {
    associatedtype Chip
}

func buy(device: any AppleDevice) {
    // .. do something
}

Also, you can use it with arrays.

enum AppleChipKind {
    case m1
    case m2
    case m3
    case m4
}

enum IntelChipKind {
    case i5
    case i7
    case i9
}

protocol AppleDevice {
    associatedtype Chip
}

class ModernMacBook: AppleDevice {
    typealias Chip = AppleChipKind
}

class OldMacBook: AppleDevice {
    typealias Chip = IntelChipKind
}

let devices: [any AppleDevice] = [
    ModernMacBook(),
    OldMacBook()
]

But there is an alternative keyword in Swift. I am talking about the some keyword. If you wanna know more about the differences between the some and the any keywords, welcome to this article then.

Conclusion

As you can see, the similarity of these tools’ names hides drastic differences under the hood. I hope this article was interesting for you, and I hope you will be interested in the following ones.