iOS 메시지 전달 메커니즘

메시지 전달 메커니즘을 사용하기 전에 메시지의 발송 원리를 알아야 한다.
하나의 방법의 실현은 반드시 세 가지 부분을 포함한다. 그것이 바로 집행 방법의 대상, 방법의 명칭, 불확정한 매개 변수이다.
SEL은 방법의 이름일 뿐이고 내부의imp가 진정한 실현 코드이다
메시지를 보내는 것은 objc_send(id, SEL, ...)를 통해 이루어진다. 먼저 대상의 클래스 대상cache, methodlist 및 부류 대상cache, methodlist에서 순서대로 SEL에 대응하는IMP를 찾는다.동적 방법을 찾지 못하고 실현되면 결의 메커니즘이 결의된다
메시지의 발송 원리를 이해한 토대에서 메시지 전달 메커니즘이 있다.
만약에 대상이 그 자체가 실현되지 않은 방법을 호출하면 컴파일할 때 경고가 나타나고 직접 실행하면crash, 즉 붕괴된다. 붕괴되는 원인은 메시지가 처리할 수 없는 대상에게 발송되기 때문이다. 왜냐하면 OC는 실행할 때 언어이기 때문에 실행 기간에 뭔가를 할 수 있기 때문이다. 이때 오류 보고를 해결하고 이 방법을 정상적으로 호출하기 위해서는 메시지 전송 메커니즘으로 처리해야 한다.일반적으로 세 개의 리시버 맨이라고 부른다.
1. 동적 방법 해석, 즉 +(BOOL)resolveInstanceMethod: (SEL)sel과
+ (BOOL)resolveClassMethod: (SEL)sel 두 가지 방법으로 처리할 수 없는 대상 방법과 클래스 방법에 대응한다.동적 추가 방법의 실현을 실현할 수 있다. 본 클래스에 추가 방법을 써서 매개 변수sel이 호출된 방법인지 판단할 수 있다. 만약에 호출된 방법을 추가 쓰기 방법으로 바꾸면 이 방법명을 호출하여 그 방법체의 효과를 실현할 수 있다.
2. 지원 수신자 단계, 즉 - (id) forwarding Target For Selector: (SEL)a Selector. 만약에 다른 클래스에서 본 클래스에서 호출된 동일한 이름을 성명하고 실현하는 방법이 있다면 이 지원 단계에서 다른 클래스의 대상이 응답할 수 있는지 판단할 수 있고 할 수 있다면 그 대상에게 방법을 맡겨 처리할 수 있으며 이 방법에서 방법을 한 대상에게 전달하여 처리할 수 있다.
3. 완전한 메시지 전달 단계, 즉 - (void) forwardInvocation: (NSInvocation*) anInvocation. 이 방법은 방법의 실현을 여러 대상에게 전달할 수 있고 효과는 다중 계승과 유사하다.
주의해야 할 것은 이 방법을 실현하기 전에 다시 써야 한다는 것이다
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
, 이 방법에서 대응 처리를 한다.
4. 위 세 가지 방법 모두 이 메시지를 처리하지 못하면 NSObject에 들어갑니다
- (void)doesNotRecognizeSelector: (SEL)aSelector에서 이상을 던지고 NSObject 분류에서 이 방법을 다시 쓰는 것을 권장하지 않습니다. 이 방법은 이상을 던지는 처리 작업과 관련이 있습니다.
총괄: 한 함수를 찾을 수 없을 때 OC는 세 가지 방법을 제공했다. 첫째, Resolve Instance Method를 호출하여 클래스에 이 함수를 추가할 기회를 준다. 둘째, forwarding Target ForSelector를 호출하여 다른 대상에게 이 함수를 실행하게 한다. 셋째, forward Invocation(함수 집행기)를 호출하여 목표 함수를 다른 형식으로 유연하게 집행한다.
모두 맞지 않으면 DoesNotRecognizeSelector를 호출하여 이상을 던집니다.

의문


Q1: 그럼 우리 마지막 리시버 맨만 쓰면 얼마나 좋을까, 왜 앞의 두 개가 더 필요할까?사실은 이 세 가지 방법의 용도와 다르다. 운행 기간에 방법을 추가하고 1을 사용한다.다른 대상에게 전달하고 방법을 바꿀 때 2를 사용한다.여러 대상에게 전달해야 할 때 3을 사용한다.
그리고 절차가 뒤로 갈수록 메시지 처리의 대가가 커지고 마지막 단계가 되면 NSInvocation 대상이 만들어진다.
Q2: 메시지 전달에는 어떤 앱 장면이 있나요?운행 기간에 어떤 방법을 추가할 수 있다. 예를 들어 Teacher류에는 팀 방법이 있고 Drug Dealer류에는 lets Cook 방법이 있다. 1번 리시버 방법을 통해 우리는 운행 기간에 Sale Drug를 팀버에 몰래 추가하는 방법 목록에 팀버가 마약 판매 기능을 갖추도록 할 수 있다. [팀버 guess What HeDo]는 실제 사용한 것은 [팀버 lets Cook]이다. 아이고, 절명독사야.
방법을 다른 대상에게 넘기고 예를 들면 테처류(블로거와 선생님이 원한이 있나...),[teacher letsCook], 대상을 운행 기간에 drugDealer로 바꿀 수 있습니다.쿡류 하나 더 주세요. lets 쿡 방법도 있는데 이번에는 쿡 마약이 아니라 쿡 요리예요.따라서 [teacher letsCook]을 통해 [drugDealer letsCook]을 실현할 수도 있고 [cook letsCook]을 실현할 수도 있다.OC가 다중 승계를 이룬 셈인데 좀 부적절하지만...
코드 예:
#import "ViewController.h"
#import "objc/runtime.h"
#import "Person.h" 

void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@" >> dynamicMethodIMP");
}

@interface ViewController ()

@property (nonatomic, strong) Person *person;

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
    self.person = [[Person alloc] init];
[self learn];
}

//+(BOOL)resolveInstanceMethod:(SEL)sel {
//    if (sel == @selector(learn)) {
//        class_addMethod([self class], sel, (IMP) dynamicMethodIMP, "v@:");
//        return YES;
//    }
//    return [super resolveInstanceMethod:sel];
//}

/**
  
 @param aSelector  
 @return    self\ nil  , 
 */
//-(id)forwardingTargetForSelector:(SEL)aSelector {
//
//    if ([self.person respondsToSelector:aSelector]) {
//        return self.person;
//    }
//    return [super forwardingTargetForSelector:aSelector];
//}
 
-(void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL invocation = [anInvocation selector];
if ([self.person respondsToSelector:invocation]) {
[anInvocation invokeWithTarget:self.person];
}
}
 
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
if (!signature) {
        signature = [self.person methodSignatureForSelector:aSelector];
}
return signature;
}
 
//-(void)doesNotRecognizeSelector:(SEL)aSelector {
//    [super doesNotRecognizeSelector:aSelector];
//}
 
@end

좋은 웹페이지 즐겨찾기