方法混淆和isa混淆是相同的吗?

11

方法交换和isa交换是一回事吗?如果不是,那么isa交换是什么?

1个回答

35

方法交换

方法交换在运行时交换了一个类的两个方法的实现。这将影响到被修改类的每个已经或者将要创建的实例。

例如: 假设您已经为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 方法,这样在调用 uppercaseString 时,就会执行 swizzled_uppercaseString 的实现(并且在调用 swizzled_uppercaseString 时,将执行 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('is a')属性,该属性描述了一个对象的类,因此您可以在运行时将给定单个对象的类型与另一种类型交换。

示例: 假设您有以下类结构:

@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);  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接