OC의 Runtime 메커니즘에 대한 동적 접근 방식 결정(Dynamic Method Resolution)
동적 방법 결정
먼저 클래스를 정의합니다.
Objective C는 동적 방법 결의라는 수단을 제공하여 우리가 실행할 때 동적으로 selector에 실현을 제공할 수 있도록 한다.우리는 +resolveInstanceMethod: 및/또는 +resolveClassMethod: 방법을 실현하고, 그 중에서 지정한 selector에 실행을 제공하면 됩니다. (실행 시 함수class addMethod를 호출해서 추가할 수 있습니다.)두 방법 모두 NSObject의 클래스 방법으로, 원형은 다음과 같습니다.
매개 변수name은 동적 결의가 필요한 selector입니다. 반환값 문서에서 동적 결의의 성공 여부를 표시합니다.그러나 위의 예에서 (메시지 전송과 관련이 없는 경우) 이 함수에서 지정한 selector에 실현을 제공하면 YES로 되돌아오든 NO로 되돌아오든 컴파일 실행이 정확하다.그러나 이 함수에서 진정으로 selector에 실현을 제공하지 않으면 YES로 돌아가든 NO로 돌아가든 실행은crash가 된다. 이치는 매우 간단하다. selector는 대응하는 실현이 없고 메시지 전달도 이루어지지 않는다.resolveInstanceMethod는 대상 방법에 대한 결의이고, resolveClassMethod는 클래스 방법에 대한 결의이다.
@interface Foo : NSObject
-(void)MissMethod;
- (void)Bar;
@end
#import "Foo.h"
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@" >> dynamicMethodIMP");
}
@implementation Foo
+ (BOOL)resolveInstanceMethod:(SEL)name {
NSLog(@" >> Instance resolving %@", NSStringFromSelector(name));
if (name == @selector(MissMethod)) {
class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:"); return YES;
}
return [super resolveInstanceMethod:name];
}
+ (BOOL)resolveClassMethod:(SEL)name {
NSLog(@" >> Class resolving %@", NSStringFromSelector(name));
return [super resolveClassMethod:name];
}
- (void)Bar {
NSLog(@" >> Bar() in Foo");
}
//- (void)MissMethod {
//
//}
@end
그리고 호출
#import "ViewController.h"
#import "Foo.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Foo *foo = [[Foo alloc] init];
[foo Bar];
[foo MissMethod];
}
인쇄된 정보:
**2017-07-02 15:58:53.578584+0800 DynamicMethodDemo[3147:601367] >> Bar() in Foo**
**2017-07-02 15:58:53.578782+0800 DynamicMethodDemo[3147:601367] >> Instance resolving MissMethod**
**2017-07-02 15:58:53.579087+0800 DynamicMethodDemo[3147:601367] >> dynamicMethodIMP**
[이미지 업로드 실패...(image-f485ae-1522657310056)]
//class_addMethod([self class], name, (IMP)dynamicMethod IMP, "v@:");
이 줄은 주석을 달았다. YES로 되돌아오지만 붕괴될 것이다. 여기서 Resolve Instance Method는 성공(YES로 되돌아오기)이 selector를 결의했다고 주장했지만 실현을 제공하지 않았고 컴파일러에 의해 발견되어 해당하는 오류 정보를 제시했다.그 반환값은 도대체 어떤 작용을 하는가. 진정한 실현을 제공하지 않고 메시지 전송 메커니즘을 제공한 상황에서 YES는 후속 메시지 전송을 하지 않겠다고 하고 NO로 돌아가면 후속 메시지 전송을 하겠다고 한다.
동적 방법의 내부 실현
1. 우선 ResolveInstanceMethod가 실현되었는지 판단하고 실현되지 않으면 NULL로 돌아가 다음 처리에 들어간다.2, 실현되면 ResolveInstanceMethod를 호출하여 되돌아오는 값을 가져옵니다.
3. 만약에 반환값이 YES라면 ResolveInstanceMethod가 selector의 실현을 제공했다고 주장하기 때문에methodlist를 다시 찾고 대응하는 IMP를 찾으면 이 실현을 되돌려준다. 그렇지 않으면 경고 정보를 알려주고 NULL을 되돌려 다음 처리에 들어간다.
4, 반환값이 NO이면 NULL로 돌아가 다음 처리에 들어간다.
가입 메시지 전달 내부 걷기objc_msgForward
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL name = [anInvocation selector];
NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name));
Proxy * proxy = [[Proxy alloc] init];
if ([proxy respondsToSelector:name]) {
[anInvocation invokeWithTarget:proxy];
}
else {
[super forwardInvocation:anInvocation];
}
}
//methodSignatureForSelector: , , methodSignature, crash。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [Proxy instanceMethodSignatureForSelector:aSelector];
}
요약:
위의 예시 시범을 통해 알 수 있듯이 동적 방법 결의는 메시지 전달보다 먼저 이루어진다.
Objective C 객체 객체에 처리할 수 없는 메시지(selector)를 보내면 컴파일러가 다음 순서로 처리됩니다.
1. 우선 이selector에 동적 방법 결의 메커니즘을 제공했는지 확인하고 제공하면 2로 전환한다.제공되지 않으면 3으로 이동합니다.2, 만약에 동적 방법 결의가 진정으로 이selector에 실현을 제공한다면 이 실현을 호출하여 메시지 발송 절차를 완성하고 메시지 전송을 완성한다.
진행하지 않을 것이다.제공되지 않으면 3으로 이동합니다.
3. 그 다음에 이selector에 메시지 전송 메커니즘을 제공했는지 확인한다. 만약에 정보를 제공하면 메시지 전송을 한다. 이때 메시지 전송이 어떻게 실현되든지 프로그램은crash가 되지 않는다.(메시지 호출의 제어권은 메시지 전송 메커니즘에 의해 완전히 처리되기 때문에 설령 메시지가
전송은 아무 일도 하지 않았고 실행도 오류가 없고 컴파일러도 오류 알림이 없습니다.);메시지 전송 메커니즘을 제공하지 않으면 4로 이동합니다.
4, 실행 오류: 식별할 수 없는 selector, 프로그램crash;
지금까지 우리는 이미 소식의 모든 원리를 이해했으니, 여기서 다시 한 번 정리하고 총결하자
1. 실례 대상이 방법을 호출할 때 방법을 idobjc 로 변환합니다msgSend(id theReceiver, SELtheSelector, ...) (이 메시지는 동적 귀속에 필요한 모든 작업을 했다)
2. 먼저 SEL에 따라 이 종류를 찾는 방법cache에서 찾으면 6으로 옮긴다.
3. 찾지 못하면 해당 방법 목록에서 찾아보세요.이 종류의 방법 목록에서 찾으면 6으로 건너뛰고cache에 캐시합니다.최근 사용 원칙에 따르면 이 방법은 다시 호출될 가능성이 높아 캐시를 하면 다음 호출에서 다시 찾는 비용을 절약할 수 있다.
4. 클래스 메소드 목록에서 해당 IMP를 찾을 수 없는 경우 클래스 구조를 통과하는 Superclass 바늘은 부류 구조의 방법 목록에서 어떤 부류의 방법 목록에서 대응하는 IMP를 찾을 때까지 6으로 이동하고cache에 추가합니다.
5. 자신과 모든 부류의 방법 목록에서 대응하는 IMP를 찾지 못하면 먼저 이selector에 동적 방법 결의 메커니즘을 제공했는지 확인한다. 만약에 동적 방법 결의가 진정으로 이selector에 실현을 제공했다면 이를 호출하여 메시지 발송 절차를 완성하고 메시지 전송을 완성한다. 그 다음에 이selector에 메시지 전송 메커니즘을 제공했는지 확인한다. 만약에 정보를 제공했다면 메시지 전송을 한다.이때 메시지 전송이 어떻게 이루어지든지 간에 프로그램은crash가 되지 않는다.(메시지 호출의 제어권은 전적으로 메시지 전송 메커니즘에 의해 처리되기 때문에 메시지 전송이 아무 일도 하지 않아도 실행에 오류가 없고 컴파일러는 오류 알림이 없다.
6. SEL에 대응하는 방법을 먼저 찾아 IMP를 실현한다.서로 다른 종류가 같은 방법에 대해 서로 다른 실현을 할 수 있기 때문에 찾은 방법은 메시지 수신자의 유형에 의존한다.
7. 메시지 수신자 대상(메시지 수신자 대상을 가리키는 지침)과 방법에 지정된 파라미터를 방법에 전달하여 IMP를 실현한다.
8. 마지막으로 방법이 실현한 반환값을 이 함수의 반환값으로 반환한다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.