方法是否会变得混乱并且是同样的混合?

时间:2016-08-10 15:18:26

标签: objective-c swizzling method-swizzling isa-swizzling

方法是否混合并且是同样的混合?如果没有,那么什么是混合?

1 个答案:

答案 0 :(得分:24)

方法调整

方法调配在运行时交换类的两种方法的实现。这将影响修改后的类的每个实例,即已创建或将要创建的实例。

实施例: 我们假设你已经为NSString写了一个类别:

@interface NSString (Swizzling)
@end
@implementation NSString (Swizzling)
- (NSString *)swizzled_uppercaseString {
    //when the method is swizzled, the original method will be called 
    //with swizzled_uppercaseString (so this will not create a stack overflow).
    NSString *result = [self swizzled_uppercaseString];
    // our custom code
    result = [result stringByAppendingString:@" (swizzled)"];
    return result;
}
@end

然后,您可以使用uppercaseString方法交换swizzled_uppercaseString - 方法的实现,因此在调用swizzled_uppercaseString时执行uppercaseString方法的实现。 (调用uppercaseString时)执行swizzled_uppercaseString的原始实现:

#import <objc/runtime.h>

NSString *sample = @"abc";

// original method is called:
NSLog([sample uppercaseString]); 

//Obtaining original and swizzled method:
original = class_getInstanceMethod([NSString class], @selector(uppercaseString));
swizzled = class_getInstanceMethod([NSString class], @selector(swizzled_uppercaseString));

//Exchange implementations here:
method_exchangeImplementations(original, swizzled);

// swizzled method is called:
NSLog([sample uppercaseString]); //prints "ABC (swizzled)"

<小时/>

ISA Swizzling

ISA swizzling修改单个对象上的属性,ISA(&#39;是一个&#39;)属性,它描述对象的类,因此您可以交换给定单个对象的类型在运行时使用其他类型。

实施例: 让我们假设你有这个类结构:

@interface Sample : NSObject
@property (nonatomic) NSString *sampleStringToLoad;
@end
@implementation Sample
@synthesize sampleStringToLoad;
@end

@interface SampleWithStringLoader :NSObject
@property (nonatomic) NSString *sampleStringToLoad;
-(void)loadString;
@end
@implementation SampleWithStringLoader
@synthesize sampleStringToLoad;
-(void)loadString {
self.sampleStringToLoad = @"abc";
}
@end

然后,您可以将课程设置为SampleWithStringLoader,以便sampleStringToLoad - 方法可用:

#import <objc/runtime.h>

Sample *sample = [Sample new];
// switch isa to new class:
object_setClass(sample, [SampleWithStringLoader class]);

// invoke method that is only in SampleWithStringLoader: 
[sample performSelector:@selector(loadString)]; 

// switch isa back to original class:
object_setClass(sample,[Sample class]); 

// Prints 'abc':
NSLog(sample.sampleStringToLoad);