[iOS/Swift] Any와 AnyObject - 모든 타입의 값을 포함할 수 있는 타입

Swift로 개발을 하다보면 Any라는 타입을 만나게 된다.

예를 들어 어떤 배열의 타입이 Any라면 그 타입에는 어떤 타입이든 들어올 수 있다는걸 뜻한다.

 

이 글에서는 Any타입의 특징과, 이와 비슷해보이는 AnyObject에대해 알아보도록 하겠다.


Any타입의 특징

Any타입을 담을 수 있는 배열에는 모든 타입이 들어올 수 있다.

var somethings: [Any] = []
somethings.append(true)
somethings.append(iPhone) // 직접 만든 클래스의 인스턴스
somethings.append("something")

개발자문서에 따르면 Any타입에 포함될 수 있는 타입은

우리가 알고있는 Int, String, Bool타입 등 기본 타입 뿐 아니라 튜플, 클로저 또는 함수타입까지 들어올 수 있다.

 

그렇다면 이 배열에 담긴 요소에 접근할 땐 어떻게 해야할까?

if let element = somethings[0] as? Bool {
    print(element)
}

if let element = somethings[1] as? Apple {
    print(element.name)
}

첫 번째요소인 Bool타입인 true에 타입캐스팅을 이용해서 접근할 수 있다.

 

그런데 여기서 Any타입의 특징이 드러나게 된다.

개발자문서에 따르면 Any의 구페적인 타입인 인스턴스는 본래 동적 타입을 유지하고 타입캐스팅을 할 수 있다고 한다.

즉, 컴파일단에서 `something[0]`의 타입은 여전히 Any타입이다. 즉, 인스턴스의 타입 자체가 바뀌지 않는다.

그리고 이 인스턴스는 런타임 단계에서 사용자가 사용할때만 타입이 Bool타입으로 사용되는 것이다.

 

컴파일 시점에 인스턴스의 타입이 결정되지 않는다는 것은 런타임에 부담을 줄 수도 있다.

즉, 컴파일 시점에 타입이 결정되지 않는 Any타입은 런타임 시점에 사용자가 해당 인스턴스에 접근하면 판단을 하게 된다.

이는 (크지는 않겠지만)어쨌든 런타임에 부담을 주게 될수도 있으므로, Any타입은 꼭 써야하는 상황이 아니면 쓰지 않는걸 추천한다.

 


그럼 AnyObject는 뭐지?

Any타입은 기본 타입을 비롯해 클래스, 구조체 등 모든 타입의 인스턴스가 담길 수 있었다.

반면 AnyObject는 클래스의 인스턴스만 담을 수 있다는 특징이 있다.

즉, 위의 코드와의 차이점은 아래와 같다.

var somethings: [AnyObject] = []
//somethings.append(true) => X
somethings.append(iPhone) // 직접 만든 클래스의 인스턴스
//somethings.append("something") => X

Any타입 배열과는 다르게 Bool타입이나 String타입을 담을 경우 오류가 나게된다.

 

이런 AnyObject타입을 사용하는 이유는 다른 타입은 들어오지 못하게하고 클래스로만 한정짓고 싶을 때 사용한다.

즉, AnyObject를 사용해 클래스에서만 사용되도록 제약사항을 줄 수 있다.

// 클래스에서만 사용되도록 제약사항 설정 => AnyObject(예전엔 class라고 쓰기도 했음)
protocol ViewConfiguration: AnyObject {
    func configureHierarchy()
    func configureLayout()
    func configureView()
}

이 프로토콜은 클래스 타입에서만 사용할 수 있게된 상태이다.

이러한 제약사항은 계층관계를 명확히 하거나, 더 나아가 최적화에 도움을 주기도 한다.

이 프로토콜이 어떻게 사용될지 많은 연산을 할 필요 없이, 클래스에만 사용되도록 한정했기 때문이다.

 

 

※참고자료

https://developer.apple.com/documentation/swift/anyobject