IOS 메소드 혼용(swizzling.)

4364 단어 iosSwizzling
OC의 혼사(swizzling)는 투명하게 한 방법을 다른 방법으로 바꾸는 것을 말한다.간단명료하게 말하면 운행할 때 방법을 바꾸는 것이다.방법을 이용하여 혼서를 하면 소스 코드가 없는 대상(시스템 대상 포함)의 행위를 바꿀 수 있다.
방법이 혼합된 코드는 비교적 직관적으로 보이는데 예를 들어 설명하자면 이전에 현지화 번역을 할 때 swizzling 방법이 사용되었다.직접 swizze 방법 awake FromNib에 가서 자신의 방법으로 바꾸어 현지화 번역을 실현한다.자세한 내용은 IOS 현지화 어플리케이션을 참조하십시오.
주로 사용되는 코드는 이 두 가지뿐이다.
+(void)load  
{  
    // Autoload : swizzle -awakeFromNib with -localizeNibObject as soon as the app (and thus this class) is loaded  
    Method localizeNibObject = class_getInstanceMethod([NSObject class], @selector(localizeNibObject));  
    Method awakeFromNib = class_getInstanceMethod([NSObject class], @selector(awakeFromNib));  
    method_exchangeImplementations(awakeFromNib, localizeNibObject);  
} 
-(void)localizeNibObject  
{   
     // ....
    // Call the original awakeFromNib method  
    [self localizeNibObject]; // this actually calls the original awakeFromNib (and not localizeNibObject) because we did some method swizzling  
} 

오늘 다시 github로 달려가서 AGi18n이라는 소스 프로젝트를 봤는데 작가는 원래의 코드를 모두 분류로 바꾸어 실현했다. 더욱 직관적으로 보였고 마찬가지로 swizzling을 통해 실현했다.
NSobject + AGi18n 분류 코드의 경우
#import "NSObject+AGi18n.h"
#import <objc/runtime.h>

@implementation NSObject (AGi18n)

//By default do nothing when localizing
- (void)localizeFromNib {
}


#pragma mark - Method swizzling

+ (void)load {
    Method awakeFromNibOriginal = class_getInstanceMethod(self, @selector(awakeFromNib));
    Method awakeFromNibCustom = class_getInstanceMethod(self, @selector(awakeFromNibCustom));
        
    //Swizzle methods
    method_exchangeImplementations(awakeFromNibOriginal, awakeFromNibCustom);
}

- (void)awakeFromNibCustom {
    //Call standard methods
    [self awakeFromNibCustom];
    
    //Localize
    [self localizeFromNib];
}

@end

위 코드는 awake From Nib과 awake From Nib Custom 방법을 교환하여 프로그램이 시작되자마자 실행합니다.이 클래스는 NSObject의 분류이기 때문에 모든 컨트롤러는 NSObject를 계승한다. 그러면 로컬 작업은 로컬화된 컨트롤러 분류에서localize FromNib을 다시 쓰기만 하면 된다. UIButton을 예로 들면 로컬 작업은 매우 간단해진다.
#import "UIButton+AGi18n.h"

@implementation UIButton (AGi18n)

- (void)localizeFromNib {

    //Replace text with localizable version
    NSArray *states = @[@(UIControlStateNormal), @(UIControlStateHighlighted), @(UIControlStateDisabled), @(UIControlStateSelected), @(UIControlStateApplication)];
    for (NSNumber *state in states) {
        NSString *title = [self titleForState:state.integerValue];
        if (title.length > 0) {
            [self setTitle:[[NSBundle mainBundle] localizedStringForKey:title value:@"" table:nil] forState:state.integerValue];
        }
    }
}

@end

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IOS 7 Programming: Pushing the Limits 라는 책에는 NSNotification Center에 관찰자를 추가할 때 로그를 인쇄하는 방법을 혼용하는 예가 나와 있다.상하 두 사례의 대비를 통해 AGi18n은 swizzling에서 부분적인 고려가 부족했다.
 
@interface NSObject(RNSwizzle)
+(IMP)swizzleSelector:(SEL)origSelector withIMP:(IMP)newIMP;
@end

@implementation NSObject(RNSwizzle)
+(IMP)swizzleSelector:(SEL)origSelector withIMP:(IMP)newIMP{
    Class class = [self class];
    Method origMethod = class_getInstanceMethod(class, origSelector);
    IMP origIMP = method_getImplementation(origMethod);
    if (!class_addMethod(self, origSelector, newIMP, method_getTypeEncoding(origMethod))) {
        method_setImplementation(origMethod, newIMP);
    }
    
    return origIMP;
}

@end

다음은 디테일을 볼게요.먼저 이 메서드에 선택기와 함수 포인터(IMP)를 전달합니다.우리가 해야 할 일은 이 방법의 현재 실현을 새로운 실현으로 바꾸고, 이후에 호출할 수 있도록 낡은 실현의 지침을 되돌려 주는 것이다.세 가지 상황을 고려해야 한다. 클래스는 이 방법을 직접 실현할 수 있고 방법은 클래스 차원 구조 중의 어떤 부류가 실현되었을 수도 있고 방법이 아예 실현되지 않았을 수도 있다.만약 이 클래스나 어떤 부류가 이 방법을 실현했다면classgetInstanceMethod는 IMP를 반환하고 그렇지 않으면 NULL을 반환합니다.
만약 방법이 근본적으로 실현되지 않았거나 어떤 부류가 실현되었다면classddMethod 추가 방법, 일반적인 덮어쓰기 방법과 같습니다.하면, 만약, 만약...addMethod가 실패했습니다. 혼서 중인 방법을 직접적으로 실현한 것을 알았습니다. 그러면 methodsetImplementation을 사용하여 이전 구현을 새 구현으로 대체합니다.
다 된 후에 원래의 IMP로 돌아가면 호출자가 되돌아오는 값을 어떻게 사용하는지는 자신의 일이다.
참조: IOS 7 Programming: Pushing the Limits

좋은 웹페이지 즐겨찾기