티스토리 뷰
Message Dispatch
Objective-C 는 클래스의 메소드가 프로퍼티를 호출할 때 해당 객체에 메시지를 보내는 방식으로 구현되어 있습니다. 그리고 이 과정이 런타임 시에 일어납니다. 이것이 message dispatch
입니다.
즉, message dispatch 는 dynamic dispatch 의 일종입니다.
message dispatch 는 오버라이딩하거나 새로 정의한 메소드들만 테이블에 유지합니다.(swift 의 dynamic dispatch 는 모든 메소드에 대한 포인터를 해당 클래스가 가짐.) 대신, 부모 클래스로의 포인터를 가지고 있기 때문에 상속받은 메소드들을 찾아갈 수 있습니다.
대신 Swift 는 이런 기능을 자체적으로 제공하지 않기때문에 message dispatch 를 Swift 에서도 사용하기 위해서는 dynamic
과 @objc
키워드가 필요합니다.
그렇다면 message dispatch 를 Swift 에서 왜 사용하나요?
message dispatch 방식은 굉장히 유연해서 런타임에 메소드를 수정하는 것부터 새로운 메소드나 프로퍼티를 수정하고, 클래스를 동적으로 만드는 것도 가능합니다. 또한, 코어데이터나 KVO 과 같은 동적인 기능은 Objective-C 런타임 덕분에 가능하기 때문입니다.
dynamic
dynamic 은 Swift 와 Objective-C 의 상호운용성 때문에 사용됩니다. 즉, Objective-C 에서 dynamic dispatch 를 Swift 에서도 사용하기 위한 역할입니다.
그래서 dynamic var
혹은 dynamic func
이 의미하는 것은 Swift 의 런타임이 아닌 Objective-C 런타임에서 사용하겠다는 것입니다. 즉, 객체한테 메시지를 보내고, 객체가 메소드의 위치를 찾아서 실행하는 과정입니다.
참고로 오직 Class 의 멤버에만 사용할 수 있습니다. 런타임에 결정할 필요가 없는 구조체와 열거형에서는 당연히 필요가 없습니다.
@objc
@objc 어노테이션을 앞에 붙이게 되면 Objective-C 런타임에 접근할 수 있게 합니다. 하지만, selector 등으로 접근하지 않는 경우는 원래의 dispatch 가 적용된다고 해요.
잠깐 !
swift-evolution/0160-objc-inference.md at master · apple/swift-evolution
위의 evolution 문서를 보게되면 Swift 4 이전에는 dynamic
어노테이션을 앞에 붙이게 되면 @objc
을 추론해서 추가했는데 이후부터는 dynamic 만 사용해서는 @objc
를 자동으로 추가해주지 않습니다.
이러한 변화는 다음 두 가지를 의미합니다.
- 미래에는 Swift 언어와 런타임이 Objective-C 런타임에 의존하지 않고 dynamic 을 지원하도록 진화할 가능성이 있고, 진화의 문을 열어두는 것이 중요하다.
- dynamic 동작이 Objective-C 런타임과연결되어 있음을 분명히 합니다.
(단, @objc
어노테이션이 적용된 프로토콜의 메소드를 구현하거나 클래스 전체에 @objcMember
어노테이션이 적용되어 있다면 자동 추론)
결과적으로 @objc dynamic
와 같이 어노테이션을 함께 사용해야 합니다.
message disaptch 를 사용해야할 때
앞서 잠깐 Swift 에서 사용되는 곳을 알아보았는데 좀 더 자세히 살펴봅시다!
1. extension 에서 함수 오버라이딩
Swift 에서는 extension 에서의 함수 오버라이딩이 불가능합니다. 이를 시도하면 다음과 같은 에러가 발생합니다.
import Foundation
class someClass {
func action() {
print("action")
}
}
class childClass: someClass { }
extension childClass {
override func action() {
print("override")
}
}
// ERROR
// Non-@objc instance method 'action()' declared in 'someClass' cannot be overridden from extension
에러 메시지를 통해 @objc 어노테이션을 추가해보겠습니다.
import Foundation
class someClass {
// ✅ @objc 어노테이션 추가.
@objc func action() {
print("action")
}
}
class childClass: someClass { }
extension childClass {
override func action() {
print("override")
}
}
// ERROR
// Cannot override a non-dynamic class declaration from an extension
여전히 에러는 존재합니다. dynamic 어노테이션을 추가해서 해결하겠습니다.
import Foundation
class someClass {
// ✅ dynamic 어노테이션 추가.
@objc dynamic func action() {
print("action")
}
}
class childClass: someClass { }
extension childClass {
override func action() {
print("override")
}
}
@objc dynamic
어노테이션을 통해 extension 에서 메소드를 오버라이딩 할 수 있습니다.
2. Selector, KVO 와 같은 Objective-C 런타임 시에만 제공되는 기능
출처
'iOS' 카테고리의 다른 글
iOS) UIView.animate(...) 왜 메모리릭이 발생하지 않나요? (2) | 2022.08.23 |
---|---|
iOS) Dispatch(6) - 성능 향상을 위한 static dispatch (0) | 2022.08.18 |
iOS) Dispatch(1) - Dynamic / Static Dispatch (0) | 2022.08.10 |
iOS) dimming view 에 대해서 (0) | 2022.07.19 |
WWDC22) Hello Swift Charts (0) | 2022.07.05 |
- YPImagePicker
- Algorithm
- APNS
- UserDefaults
- WWDC22
- IOS
- 서버통신
- watchOS
- 2022 KAKAO TECH INTERNSHIP
- rxswift
- CloneCoding
- OpenSourceLibrary
- WWDC
- SwiftUI
- Protocol
- Widget
- urlsession
- Swift
- Notification
- github
- RxCocoa
- Firebase
- configurable widget
- Objective-C
- containerBackground
- projectsetting
- WidgetKit
- async/await
- MOYA
- MVVM
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Total
- Today
- Yesterday