최근에 공부를 하면서 AnyObject의 정확한 의미를 알지 못해 겪은 오류가 있어, 이번에 확실히 이해하고 넘어가기 위해 AnyObject에 대해서 알아보겠습니다.
protocol MyViewControllerDelegate {
func someFunction()
}
class MyViewController: UIViewController {
weak var delegate: MyViewControllerDelegate? // Error!
}
에러의 내용은 다음과 같습니다.
'weak' must not be applied to non-class-bound 'MyViewControllerDelegate'; consider adding a protocol conformance that has a class bound
weak은 non-class의 범위(?)에 적용될 수 없다. 즉, 지금 이 delegate라는 프로퍼티가 가지고있는 타입이 반드시 class 타입이 올 것이라는 보장이 없어 weak이라는 키워드를 사용할 수 없다는 의미로 해석됩니다.
그래서 weak이라는 키워드를 달아주기 위해서는, MyViewControllerDelegate라는 프로토콜이 반드시 class타입이 될 것이라는 확신을 줘야합니다. 이때 사용하는 것이 AnyObject입니다.
protocol MyViewControllerDelegate: AnyObject {
func someFunction()
}
class MyViewController: UIViewController {
weak var delegate: MyViewControllerDelegate?
}
AnyObject?
The protocol to which all classes implicitly conform.
AnyObject는 공식문서에 모든 클래스들이 반드시 준수하고 있는 프로토콜이라고 나와있습니다.
이 AnyObject는 아직 구체적으로 타입이 정해지지 않은 객체에 대해 유연함을 주고싶거나, Objective-C의 메서드나 프로퍼티의 반환 값이 타입이 정해지지 않은 결과가 나올때 AnyObject를 사용하여 이를 처리할 수 있습니다.
또한 AnyObject를 사용하여 모든 클래스, 클래스 타입 또는 class-only 프로토콜의 인스턴스에 대한 concrete 타입으로 사용할 수 있습니다.
예를들어 위의 예시를 다시 가져와보겠습니다.
protocol MyViewControllerDelegate: AnyObject {
func someFunction()
}
class MyViewController: UIViewController {
weak var delegate: MyViewControllerDelegate?
}
이 코드에서는 MyViewControllerDelegate에 AnyObject를 채택하여 MyViewControllerDelegate를 class-only 프로토콜로 만들어 주었습니다. 그렇기 때문에 아래의 MyViewController에서 delegate 프로퍼티는 MyViewControllerDelegate의 옵셔널 타입이고, 이는 class 즉, 레퍼런스타입이므로 weak 키워드를 앞에 붙일 수 있게 되는것입니다.
또다른 예시를 보겠습니다.
class Person {
let name: String
init(name: String) {
self.name = name
}
}
let myPerson = Person(name: "Joons")
let anyObject: AnyObject = myPerson
Person이라는 class를 만들었습니다. 이후에 myPerson이라는 Person 타입의 인스턴스를 만들었고, 이를 anyObject라는 AnyObject 타입의 인스턴스 또한 myPerson을 참조하게 만들어 주었습니다.
let anyObject: AnyObject = myPerson 이 가능한 이유는 아까 위에서 살펴봤던 AnyObject가 모든 클래스 타입의 Concrete타입이 될 수 있기 때문입니다.
이번에는 Person 클래스의 name 프로퍼티를 var로 바꾸고, AnyObject 타입을 Person 타입으로 타입캐스팅까지 해보겠습니다.
print(myPerson.name) // Joons
myPerson.name = "JoonSwift"
print(myPerson.name) // JoonSwift
if let anyPerson = anyObject as? Person {
print(anyPerson.name) // JoonSwift
}
if let 과 as? 를 통해 타입캐스팅을 진행하였고, anyPerson이라는 상수에 name을 확인해보니, myPerson의 name을 바꿔준 값이 그대로 출력되는 것을 확인할 수 있습니다.
정리
AnyObject는 결국 어떤 타입이 올지는 모르겠지만, 클래스, 클래스타입, class-only 프로토콜 이런것들이 올것이다~ 라고 Swift에게 미리 알려주는 역할을 하고, 그럼 이렇게 명시해둔 것들을 모두 레퍼런스 타입 처럼 사용할 수 있게 해줍니다.
또한 제가 실수했었던 protocol 에서 AnyObject를 채택하면, 이 protocol은 class-only 프로토콜이야. 라고 Swift에게 말해주는 것이라고 할 수 있을 것 같습니다. (예전의 코드들을 보면 protocol MyProtocol: class) 이렇게 class라는 키워드를 많이 사용했다는 것 또한 이해를 돕는데 도움이 되었습니다..
참조
https://developer.apple.com/documentation/swift/anyobject
'Swift' 카테고리의 다른 글
Swift ) Designated Initializer, Convenience Initializer (0) | 2022.05.02 |
---|---|
Swift ) Difference between components and split (0) | 2022.04.19 |
Swift ) URL에 한글이 들어갈때? (addingPercentEncoding) (0) | 2022.03.29 |
Type Methods (static func & class func) (0) | 2022.03.23 |
Sequence (0) | 2022.01.28 |