method swizzling 和 isa swizzling 是一回事吗?
Are method swizzling and isa swizzling the same thing?
method swizzling 和 isa swizzling 是一回事吗?如果不是,那么什么是 swizzling?
方法调配
方法调配在运行时交换class的两个方法的实现。这将影响修改后的 class.
的每个已经创建或将要创建的实例
示例:
假设您已经为 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 调配
ISA swizzling 修改单个对象上的 属性,ISA ('is a') 属性,它描述了对象的 class,因此您可以 在运行时将给定的单个对象的类型与另一种类型交换。
示例:
假设您有这个 class 结构:
@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
然后您可以将 class 设置为 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);
method swizzling 和 isa swizzling 是一回事吗?如果不是,那么什么是 swizzling?
方法调配
方法调配在运行时交换class的两个方法的实现。这将影响修改后的 class.
的每个已经创建或将要创建的实例示例: 假设您已经为 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 调配
ISA swizzling 修改单个对象上的 属性,ISA ('is a') 属性,它描述了对象的 class,因此您可以 在运行时将给定的单个对象的类型与另一种类型交换。
示例: 假设您有这个 class 结构:
@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
然后您可以将 class 设置为 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);