Effective Objective-C 2.0 고품질 iOS 및 OS X 코드 이해 메시지 전달 메커니즘 작성

4776 단어
1. 대상이 상응하는 선택자를 선택할 수 없으면 메시지 전달 절차에 들어간다.
2. 운행기의 동적 방법 해석 기능을 통해 우리는 어떤 방법이 필요할 때 이를 클래스에 추가할 수 있다.
3. 대상은 해석할 수 없는 일부 선택자를 다른 대상에게 전달하여 처리할 수 있다.
4. 상기 두 단계를 거쳐 선택자를 처리할 수 없으면 완전한 메시지 전송 메커니즘을 가동한다.
5. 메시지 전달은 두 가지 부분으로 나뉜다.
첫 번째 단계는 수신자가 속한 클래스를 조회하여 현재 '위치의 선택자' (unknown selector) 를 처리할 수 있는지 확인하는 것입니다. 이것은 '동적 방법 해석' (dynamic method resolution) 이라고 합니다.
두 번째 단계는 지원을 준비하는 수신자가 있으면 그 대상에게 전달하고 그렇지 않으면 완전한 메시지 전송 메커니즘을 가동한다.
운행 기간 시스템은 메시지와 관련된 모든 세부 사항을 NSInvocation 대상에 봉하여 수신자에게 현재 처리되지 않은 이 메시지를 해결할 수 있는 마지막 기회를 준다.
6. 동적 방법 해석
대상은 해석할 수 없는 소식을 받아들인 후 먼저 그 소속 클래스의 다음 클래스 방법을 호출한다.
+ (BOOL)resolveInstanceMethod:(SEL)selector

id autoDictionaryGetter(id self, SEL _cmd);
void autoDictionarySetter(id self, SEL _cmd, id value);

+ (BOOL)resolveInstanceMethod:(SEL)selector
{
     NSString *selectorString = NSStringFromSelector(selector);
     if (/* selector is from a @dynamic property */)
     {
          if([selectorString hasPrefix:@“set”])
          {
               class_addMethod(self, selector, (IMP)autoDictionarySetter, “v@:@“);
          }else {
               class_addMethod(self, selector, (IMP)autoDictionaryGetter, “@@:“);
          }
          return YES;
     }
     return [super resolveInstanceMethod:selector];
}

7. 지원 접수자
- (id)forwardingTargetForSelector:(SEL)selector
주: 우리는 이 단계를 거쳐 전송된 정보를 조작할 수 없습니다. 지원 수신자에게 다시 보내기 전에 메시지 내용을 수정하려면 완전한 메시지 전송 메커니즘을 통해 해야 합니다.
8. 완전한 소식을 전달한다.
먼저 NSInvocation 객체를 작성하여 처리되지 않은 메시지와 관련된 모든 세부 사항을 캡슐화합니다.
이 대상은 하위 선택, 목표 (targer), 인자를 포함합니다.
NSInvocation 객체를 다시 트리거하면 메시지 디스패치 시스템이 직접 나서서 대상 객체에 메시지를 할당합니다.
- (void)forwardInvocation:(NSInvocation*)invocation;
이 방법을 실현할 때, 어떤 호출 작업이 본 클래스에서 처리되지 않는 것을 발견하면, 초클래스의 동명 방법을 호출해야 한다.
이렇게 하면 상속 시스템의 모든 클래스가 이 호출 요청을 NSObject까지 처리할 수 있습니다.
마지막으로 NSObject 클래스의 방법을 호출하면, 이 방법은 이상을 던지기 위해 'DoesNotRecognizeSelector' 를 호출합니다.
이 이상은 선택자가 최종적으로 처리되지 않았음을 나타낸다.
9. 완전한 예로 동적 방법의 해석을 보여준다
디자인 사고방식: 개발자가 속성 정의를 추가하고 @dynamic로 설명하며 클래스는 관련 속성 값의 저장과 가져오는 작업을 자동으로 처리합니다.
@interface EOCAutoDictionary : NSObject
@property (nonatomic, strong) NSString *string;
@property (nonatomic, strong) NSNumber *number;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) id opaqueObject;
@property (nonatomic, strong) NSMutableDictionary *backingStore;
@end 

@interface EOCAutoDictionary
@dynamic string, number, date, opaqueObject;

- (id)init {
     if((self = [super init])){
          _backingStore = [NSMutableDictionary new];
     }
     return self;
}

+ (BOOL)resolveInstanceMethod:(SEL)selector
{
     NSString *selectorString = NSStringFromSelector(selector);
     if([selectorString hasPrefix:@“set”])
     {
         class_addMethod(self, selector, (IMP)autoDictionarySetter, “v@:@“);
      }else {
         class_addMethod(self, selector, (IMP)autoDictionaryGetter, “@@:“);
      }
      return YES; 
}
@end

개발자가 처음으로 EOCAutoDictionary 실례에서 어떤 속성에 접근했을 때, 실행기 시스템은 필요한 선택자가 직접적으로 실현되지 않았고, 합성되지 않았기 때문에 대응하는 선택자를 찾지 못했다.그래서 ResolveInstanceMethod를 호출합니다:class 를 호출합니다addMethod 메서드.
Getter 함수는 다음 코드로 수행할 수 있습니다.
id autoDictionaryGetter (id self, SEL _cmd)
{
     // Get the backing store from the object 
     EOCAutoDictionary *typedSelf = (EOCAutoDictionary*)self;
     NSMutableDictionary *backingStore = typedSelf.backingStore;
     
     // The key is simply the selector name
     NSString *key = NSStringFromSelector(_cmd);
     
     // Return the value
     return [backingStore objectForKey:key];
}

setter 함수는 다음과 같이 쓸 수 있습니다.
void autoDictionarySetter(id self,SEL _cmd, id value)
{
     // Get the backing store from the object;
     EOCAutoDictionary *typedSelf = (EOCAutoDictionary*)self;
     NSMutableDictionary *backingStore = typedSelf.backingStore;
 
     // for “ :setOpaqueObject:” tobe “opaqueObject”
     NSString *selectorString = NSStringFromSelector(_cmd);
     NSMutableString *key = [selectorString mutableCopy];

     [key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)];

     [key deleteCharactersInRange:NSMakeRange(0, 3)];
     
     NSString 8lowercaseFistChar = [[key substringToIndex:1] lowercaseString];
     [key replaceCharactersInRange:NSMakeRange(0,1) withString:lowercaseFirstChar];

     if(value)
          [backingStore setObject:value forKey:key];
     else
          [backingStore removeObjectForKey:key];
}

iOS의 CALayer는 이 예와 유사하게 구현됩니다.CALayer를 키 값 인코딩에 호환되는 컨테이너 클래스(key-value-coding-compliant)로 만들기;
Effective Objective-C 2.0에서 고품질 iOS와 OS X 코드를 작성하는 52가지 유효한 방법
, 서적 구매, 작가 및 번역자 지원 부탁드립니다.

좋은 웹페이지 즐겨찾기