진급편 제7기: 메시지 전달 초기 체험

인터넷에서 많은 파트너들이 정보를 전달하는 블로그, 스티커를 봤는데 런타임에서 자주 사용하는 기술인 것 같아요. 처음에는 무슨 소용이 있는지 몰랐지만 관련 코드를 일부 두드린 후에 해결해야 할 것은 우리가 대상을 만들고 그 방법을 호출할 때 이 방법이 성명만 있을 뿐 실현되지 않으면 프로그램 Crash가 떨어진다는 거예요.이러한 상황을 방지하기 위해 우리는 런타임의 메시지 전달 메커니즘으로 프로그램의 Crash를 방지한다.
또한 우리가 여러 대상을 처리할 때 여러 대상을 통해 특정한 클래스 안의 방법을 호출하여 정보를 전달하는 것을 고려할 수 있다. 그러면 이것은 우리로 하여금 통일화시킬 수 있다. 공장 방법과 같이 우리가 어떤 하위 클래스의 방법을 호출하고 싶을 때 먼저 부류의 방법을 사용할 수 있다. 메시지 전달에서 우리는 여러 대상을 통해 특정한 종류의 방법을 호출하여 비슷한 효과를 실현할 수 있다.진짜 신기해요. 유목유.
됐어, 쓸데없는 말은 그만하고, 코드도 권위도 없고, 코드에 오르자.
우선 우리는 하나의 클래스를 만들고, 하나의 방법을 설명하지만, 그것을 실현하지 못한다
 
@interface SWHModel : NSObject

- (void)beginUp;

@end

다음은 Controller에서 그것을 호출해서 어떤 효과가 있는지 봅시다
맞아, 예상대로 프로그램 크래쉬가 떨어졌어 대상이 대응하는 방법을 찾지 못했으니까
 
- (void)buildData {
    SWHModel *model = [[SWHModel alloc] init];
    [model beginUp];
}

OK, 메시지를 전달하는 첫 번째 방법을 사용합니다
 
void begin (id self, SEL _cmd) {
    NSLog(@"%@ %s", self, sel_getName(_cmd));
}

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

여기의classddMethod 방법은 현재 클래스의 동태에 지시 방법을 추가하고, 현재 함수의 세 번째 인자는 C의 함수를 추가합니다. 그래서 우리는 여기에 C 함수를 만듭니다. 또한 "v@:"은void self Selector를 표시합니다.
C 함수로 바로 옮겨지는 걸 알게 될 거예요.
그리고 두 번째 방법입니다.
 
- (id)forwardingTargetForSelector:(SEL)aSelector {
    return [[SWHNextModel alloc] init];
}

맞아요. 저는 SWHNext 모델 클래스에서 이 방법을 설명하고 실현했습니다. 그리고 우리는 메시지를 전송하여 현재 대상을 새로 만든 이 클래스 대상으로 직접 전달했습니다. 그러면 이 클래스 대상 안의 방법을 직접 호출할 수 있습니다.
마지막으로 세 번째 방법입니다.
가장 안전한 방법입니다. 저는 보통 세 번째 방법을 직접 씁니다.
 
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSString *sel = NSStringFromSelector(aSelector);
    if ([sel isEqual:@"beginUp"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL selector = [anInvocation selector];
    SWHNextModel *model = [[SWHNextModel alloc] init];
    if ([model respondsToSelector:selector]) {
        [anInvocation invokeWithTarget:model];
    }
}

사실 세 번째 방법은 앞의 두 가지를 합친 것이다. 먼저 이 대상은 NSMethod Signature를 가져와서 방법 라벨을 얻는다. 이때 우리는 그것에 대한 판단을 하고 필요한 type을 준다. 다음에 Invocation 방법에 새로운 대상을 만들고 깨우면 우리는 바로 새로운 대상 안의 방법을 호출할 것이다.
하, 맞아요. 이 세 가지 방법은 모두 상술한 문제를 해결할 수 있어요. 즉, 모두 메시지 전달을 실현할 수 있어요.
재밌긴 재밌네.
나중에 다른 방법을 조사해 볼게요.

좋은 웹페이지 즐겨찾기