Swift

Swift ) What is AnyObject?

JoonSwift 2022. 4. 6. 19:02

최근에 공부를 하면서 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?
}

이 코드에서는 MyViewControllerDelegateAnyObject를 채택하여 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

 

Apple Developer Documentation

 

developer.apple.com