替换 objective C 中的 class 方法并调用原始实现
Replacing a class method in objective C and calling original implementation
我正在尝试用我自己的实现替换 UIImage 的 class 方法。
在某些情况下,我的实现可能只想调用原始的 UIImage 实现。
这是我的代码
#import "UIImage+SkinnedImage.h"
#import <objc/runtime.h>
@interface UIImage (SkinnedImagePrivate)
+ (UIImage *)originalImageNamed:(NSString*)name;
@end
@implementation UIImage (SkinnedImage)
+ (void)allowSkinning {
Method imageNamedMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));
IMP originalImageNamedIMP = class_getMethodImplementation_stret([UIImage class], @selector(imageNamed:));
Method swizzled = class_getClassMethod([UIImage class], @selector(skinnedImageNamed:));
method_exchangeImplementations(imageNamedMethod, swizzled);
const char *signatureEnconding = method_getTypeEncoding(imageNamedMethod);
class_addMethod([UIImage class], @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
}
+ (UIImage *)skinnedImageNamed:(NSString *)name {
//XXX
return [UIImage originalImageNamed:name];
}
@end
+ (void)allowSkinning
被调用。
+ (UIImage *)skinnedImageNamed:(NSString *)name
被调用而不是 + (UIImage *)imageNamed:(NSString *)name;
return [UIImage originalImageNamed:name];
崩溃并出现错误:
reason: '+[UIImage originalImageNamed:]: unrecognized selector sent to
class
为什么 class_addMethod([UIImage class], @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);未能为我提供实施方案?
请注意函数 class_addMethod returns true
此行将实例方法 -originalImageNamed:
添加到 UIImage
:
class_addMethod([UIImage class], @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
您可以将其更改为:
class_addMethod(object_getClass([UIImage class]), @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
或者,等价地:
class_addMethod(objc_getMetaClass("UIImage"), @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
class 方法是 class 的元 class 上的实例方法。因此,向该元 class 添加实例方法会向 class.
添加 class 方法
您对 class_getMethodImplementation_stret()
的调用也存在类似问题。该函数获取实例方法的实现。因此,如果你想得到一个class方法,你必须通过class的meta-class:
IMP originalImageNamedIMP = class_getMethodImplementation(object_getClass([UIImage class]), @selector(imageNamed:));
或者,因为您已经有了相应的 Method
,您可以这样做:
IMP originalImageNamedIMP = method_getImplementation(imageNamedMethod);
顺便问一下,你为什么要使用 class_getMethodImplementation_stret()
? +imageNamed:
没有 return 结构。
我正在尝试用我自己的实现替换 UIImage 的 class 方法。
在某些情况下,我的实现可能只想调用原始的 UIImage 实现。
这是我的代码
#import "UIImage+SkinnedImage.h"
#import <objc/runtime.h>
@interface UIImage (SkinnedImagePrivate)
+ (UIImage *)originalImageNamed:(NSString*)name;
@end
@implementation UIImage (SkinnedImage)
+ (void)allowSkinning {
Method imageNamedMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));
IMP originalImageNamedIMP = class_getMethodImplementation_stret([UIImage class], @selector(imageNamed:));
Method swizzled = class_getClassMethod([UIImage class], @selector(skinnedImageNamed:));
method_exchangeImplementations(imageNamedMethod, swizzled);
const char *signatureEnconding = method_getTypeEncoding(imageNamedMethod);
class_addMethod([UIImage class], @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
}
+ (UIImage *)skinnedImageNamed:(NSString *)name {
//XXX
return [UIImage originalImageNamed:name];
}
@end
+ (void)allowSkinning
被调用。+ (UIImage *)skinnedImageNamed:(NSString *)name
被调用而不是+ (UIImage *)imageNamed:(NSString *)name;
return [UIImage originalImageNamed:name];
崩溃并出现错误:
reason: '+[UIImage originalImageNamed:]: unrecognized selector sent to class
为什么 class_addMethod([UIImage class], @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);未能为我提供实施方案?
请注意函数 class_addMethod returns true
此行将实例方法 -originalImageNamed:
添加到 UIImage
:
class_addMethod([UIImage class], @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
您可以将其更改为:
class_addMethod(object_getClass([UIImage class]), @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
或者,等价地:
class_addMethod(objc_getMetaClass("UIImage"), @selector(originalImageNamed:), originalImageNamedIMP, signatureEnconding);
class 方法是 class 的元 class 上的实例方法。因此,向该元 class 添加实例方法会向 class.
添加 class 方法您对 class_getMethodImplementation_stret()
的调用也存在类似问题。该函数获取实例方法的实现。因此,如果你想得到一个class方法,你必须通过class的meta-class:
IMP originalImageNamedIMP = class_getMethodImplementation(object_getClass([UIImage class]), @selector(imageNamed:));
或者,因为您已经有了相应的 Method
,您可以这样做:
IMP originalImageNamedIMP = method_getImplementation(imageNamedMethod);
顺便问一下,你为什么要使用 class_getMethodImplementation_stret()
? +imageNamed:
没有 return 结构。