본문 바로가기

Swift

Any/AnyObject

728x90

타입 캐스팅의 연장선으로 알면 좋을 개념입니다.

 

Any/Any Object

타입 캐스팅을 수행할 때 일반적으로 상속 관계에 있는 클래스끼리만 캐스팅이 가능하지만, Any와 AnyObject 타입을 사용할 경우 상속 관계에 있지 않아도 타입 캐스팅을 할 수 있습니다. 

 

상속 관계에 있을 때 Up Casting(=as)와 Down Casting(= as? as!)을 할 수 있습니다. 그리고 앞서 말한 것처럼 Any와 AnyObject 타입인 경우 상속 관계가 아니어도 타입 캐스팅을 할 수 있습니다. 

 

먼저, Any와 AnyObject에 대해서 알아보도록 하겠습니다. 

 

Any : 모든 타입

모든 타입을 저장할 수 있도록 하는 것이 Any입니다.

 

Swift는 타입에 민감한 언어입니다. 그래서 만약, Int형 배열을 선언한다면 다음과 같이 Int형 이외의 타입을 저장할 수 없습니다.

var nums: [Int] = []
 
nums.append(1)
nums.append(1.0)                 // Cannot convert value of type 'Double' to expected argument type 'Int'
nums.append("sokyte")            // Cannot convert value of type 'String' to expected argument type 'Int'
nums.append(false)               // Cannot convert value of type 'Bool' to expected argument type 'Int

 

위와 같은 상황에서 모든 타입을 저장할 수 있게 해주는 Any타입으로 명시하면 다음과 같습니다.

var things: [Any] = []
 
things.append(1)
things.append(1.0)
things.append("sokyte")
things.append(false)        
things.append(Human.init()))        
things.append({ print("I am sokyte!") })

Value타입(구조체, 열거형), Reference타입(클래스, 클로저)에 상관없이 Any 타입은 모두 저장이 가능합니다.

 

Any Object : 모든 클래스 타입을 저장

Any보다 타입 앞에 클래스 타입이라는 수식어가 붙은 것을 확인할 수 있습니다.

Any가 구조체/열거형/클래스 .. 등의 어떤 타입이든지 간에 모두 허용했다면, AnyObject는 보다 까다로운 것을 말합니다.

 

타입이 AnyObject로 선언될 경우, 클래스 타입만 저장할 수 있습니다.

var things: [AnyObject] = []
 
things.append(1)                                // Argument type 'Int' expected to be an instance of a class
things.append(1.0)                              // Argument type 'Double' expected to be an instance of a class
things.append("sokyte")                         // Argument type 'String' expected to be an instance of a class
things.append(false)                            // Argument type 'Bool' expected to be an instance of a class
things.append(Teacher.init()))        
things.append({ print("I am sokyte!") })        // Argument type '()->()' expected to be an instance of a class

그러므로 위와 같이 코드를 작성하면, 클래스 타입인 Teacher 인스턴스를 제외하고 모두 에러가 납니다.

구조체, 열거형는 값 타입이므로 안되고 참조 타입인 클로저도 클래스가 아니기 때문에 안됩니다.

 

다만, 클래스 타입이라면 모두 저장이 가능합니다.

things.append(Teacher.init()))        
things.append(Student.init()))

따라서 위와 같이 클래스 타입이 Human이든지, Teacher이든지에 상관없이 모든 클래스 객체를 저장할 수 있습니다.

 

Any & AnyObject의 타입 캐스팅

Any 또는 AnyObject는 런타임 시점에 타입이 결정되기 때문에 컴파일 시점에서는 해당 타입에 대해 알 수 없습니다.

그렇기 때문에 해당 타입의 멤버에도 접근할 수 없습니다.

 

var name: Any = "sokyte"

따라서 위와 같이 Any로 선언한 경우, string 타입임에도 불구하고 name에 대고 string의 메서드 또는 프로퍼티에 접근하려고 하면 다음과 같이 자동완성이 나타나지 않고 에러가 나는 것을 확인할 수 있습니다. 

 

🤔 만약 Any타입인 name을 String으로 접근해서 사용하고 싶다면?

if var name = name as? String {
    name.append("후리방구")
}

✅ 타입 캐스팅 이후에 사용할 수 있습니다.

 

📌 Any와 AnyObject를 남발하지 말자 !!

Swift는 타입에 민감한 언어입니다. 그런데 Any와 AnyObject는 이를 조금 유연하게 만들어 주므로 Swift의 성격과 그렇게 잘 맞는 문법이라고 할 수 없고 위에서 말한 것과 같이 런타임 시점에서 타입이 결정되기 때문에 만약 오류가 난다면, 런타임 오류로 빠지게 됩니다.

또한, Any로 선언될 경우 해당 타입으로 접근해서 사용하고 싶은 경우 타입 캐스팅을 따로 해야 합니다.

그렇기 때문에, 적절히 필요한 상황에서 사용하면 유연하게 사용할 수 있지만,
꼭 필요한 경우가 아니라면 남발하지 않는 것이 좋습니다. 

'Swift' 카테고리의 다른 글

프로퍼티 - 저장 프로퍼티  (0) 2022.07.27
some  (0) 2022.04.29
mutating  (0) 2022.04.29
Generic  (0) 2022.04.29
atomic VS nonatomic  (0) 2022.04.26