2014-11-21 38 views
1

我想嘗試使用方法Swizzling來清楚地瞭解它是如何工作的。看看這個代碼:http://nshipster.com/method-swizzling/。 我創建了一個類和類別,這裏是代碼Objective-C方法Swizzling示例不起作用

#import <Foundation/Foundation.h> 

@interface CustomClass : NSObject 

-(void) originalMethod; 

@end 

類的實現

#import "CustomClass.h" 

@implementation CustomClass 

-(id) init { 
    self = [super init]; 
    return self; 
} 

-(void) originalMethod { 
    NSLog(@"I'm the original method"); 
} 

@end 

分類標題:

#import "CustomClass.h" 

@interface CustomClass (CustomCategory) 

-(void) newMethod; 

@end 

分類實施

#import "CustomClass+CustomCategory.h" 
#include <objc/runtime.h> 

@implementation CustomClass (CustomCategory) 

-(void) newMethod { 
    [self newMethod]; 
    NSLog(@"I'm the new method"); 
} 

+(void) load { 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     Class class = [self class]; 

     // When swizzling a class method, use the following: 
     // Class class = object_getClass((id)self); 

     SEL originalSelector = @selector(originalMethod:); 
     SEL swizzledSelector = @selector(newMethod:); 

     Method originalMethod = class_getInstanceMethod(class, originalSelector); 
     Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 

     BOOL didAddMethod = class_addMethod(class, 
              originalSelector, 
              method_getImplementation(swizzledMethod), 
              method_getTypeEncoding(swizzledMethod)); 

     if (didAddMethod) { 
      class_replaceMethod(class, 
           swizzledSelector, 
           method_getImplementation(originalMethod), 
           method_getTypeEncoding(originalMethod)); 
     } else { 
      method_exchangeImplementations(originalMethod, swizzledMethod); 
     } 
    }); 
} 

@end 

這裏是主要的:

#import <Foundation/Foundation.h> 
#import "CustomClass.h" 
#import "CustomClass+CustomCategory.h" 

int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
     CustomClass *cc = [[CustomClass alloc] init]; 
     [cc newMethod]; 
    } 
    return 0; 
} 

當我打電話[cc newMethod],我得和無限循環,不應根據我鏈接的文章出現。 我看不到在這段代碼中的錯誤。

+0

您確定正在調用加載方法嗎? – Kegluneq 2014-11-21 13:29:30

+0

@ user1963877不,我沒有檢查過它。它應該被調用,因爲它是NSObject中的一個方法。 – AR89 2014-11-21 13:33:59

+0

下面是關於使用'+(void)load' [link](https://www.mikeash.com/pyblog/friday-qa-2009-05-22-objective-c-class-loading-and-initialization。 HTML)。注意你的教程涉及普通的CocoaTouch應用程序(使用ui線程等),而你在基本裸體的hello世界程序中嘗試它時,它的行爲可能會有所不同。 – Kegluneq 2014-11-21 13:43:08

回答

1

的問題是在語法,而不是

SEL originalSelector = @selector(originalMethod:); 
SEL swizzledSelector = @selector(newMethod:); 

我應該寫:

SEL originalSelector = @selector(originalMethod); 
SEL swizzledSelector = @selector(newMethod); 

的Xcode給了我只是一個警告,所以我不認爲選擇的名字是錯的。

0
class_replaceMethod(class, 
         swizzledSelector, 
         method_getImplementation(originalMethod), 
         method_getTypeEncoding(originalMethod)); 

應該不是method_getImplementation(originalMethod)swizzledMethod

+0

我試過了,結果一樣 – AR89 2014-11-22 10:25:49

0

好像你混寫類方法:

Class class = [self class]; 

指向+load上下文元類,儘量明確的指定,即

Class class = [CustomClass class]; 
// or 
Class class = self; 

另外,什麼@bbum說

0
  1. 錯誤的語法,運行時會發送不同的消息。

    SEL originalSelector = @selector(originalMethod); 
    SEL swizzledSelector = @selector(newMethod); 
    
  2. 如果第一種方式沒有效果。試試看:

    BOOL didAddMethod = 
    class_addMethod(class, originalSelector, 
           method_getImplementation(swizzledMethod), 
           method_getTypeEncoding(swizzledMethod)); 
    
    if (didAddMethod) { 
        method_exchangeImplementations(originalMethod, swizzledMethod); 
    
    } 
    

交易所的實現可能影響。