Ios 在方法中添加其他行为而不进行子类化
我需要为我需要扩展的方法添加额外的行为,即实现如下所示的方法Ios 在方法中添加其他行为而不进行子类化,ios,objective-c,oop,objective-c-blocks,Ios,Objective C,Oop,Objective C Blocks,我需要为我需要扩展的方法添加额外的行为,即实现如下所示的方法 - (void)extendMethod:(SEL)selector forClass:(Class)class withCompletionBlock:(void (^)(void))completionBlock; 因此,每次Class实例调用带有SELselector的方法时,都应该调用我的完成块 我尝试过方法swizzling,但遇到了一些问题:我希望调用原始的方法实现 我需要的与子类化非常相似,但这应该在不使用子类化的情况
- (void)extendMethod:(SEL)selector forClass:(Class)class withCompletionBlock:(void (^)(void))completionBlock;
因此,每次Class
实例调用带有SEL
selector的方法时,都应该调用我的完成块
我尝试过方法swizzling,但遇到了一些问题:我希望调用原始的方法实现
我需要的与子类化非常相似,但这应该在不使用子类化的情况下实现
更新:
例如,我有UIViewController
的子类,名为MyViewController
MyViewController
具有-(void)viewDidLoad
方法。在应用程序中的某个地方,我调用方法
[methodExtender extendMethod:@selector(viewDidLoad)
forClass:[MyViewController class]
withCompletionBlock:^{
NSLog(@"view did load called");
}];
因此,在调用MyViewController每个实例的viewDidLoad方法后,我的完成块被调用。我不确定您想如何使用选择器,但您可以尝试使用Objective-C中称为“Categories”的机制扩展任何类(即使是没有实现文件的类)
UIButton+extendMethod.h
在头文件中声明您的方法,并在*.m文件中实现它
使用
如果您想在*.h文件导入中使用视图控制器
#导入“UIButton+extendMethod.h”
然后你可以这样调用你的方法:
UIButton*button=[[UIButton alloc]init];
[按钮扩展方法:@selector(yourMethod:)]代码>Swizzling确实允许您调用原始实现,尽管它有点让人困惑。由于实现在swizzled之后交换,因此可以使用swizzled方法的选择器调用原始实现:
- (void)mySwizzledImplementation {
// do stuff
// now call original implementation (using swizzled selector!)
[self mySwizzledImplementation];
// do more stuff
}
另请参见没有子类化就无法(再)模拟继承。过去常常会摆姿势,只剩下方法旋转(虽然不如摆姿势优雅)。下面是一种在能够调用原始实现的同时正确执行方法swizzling的方法
int swizzle_instance_methods(Class class, SEL selector, IMP replacement, IMP *store) {
@synchronized(class) {
Method method = class_getInstanceMethod(class, selector);
IMP original_imp = NULL;
if (method != NULL) {
const char *type = method_getTypeEncoding(method);
IMP original_imp = class_replaceMethod(class, selector, replacement, type);
if (original_imp == NULL)
original_imp = method_getImplementation(method);
if (original_imp != NULL && store != NULL) {
*store = original_imp;
}
}
return (original_imp != NULL);
}
}
+ (void) load
{
static IMP originalMethodImpl = NULL;
IMP customMethodImpl = imp_implementationWithBlock(^(id self_) {
NSString *descr = ((NSString(*)(id,SEL))originalMethodImpl)(self_, @selector(description);
return [NSString stringWithFormat:@"<--- %@ --->",descr];
});
swizzle_instance_methods([self class], @selector(description), customMethodImpl, &originalMethodImpl);
}
int swizzle\u实例\u方法(类、SEL选择器、IMP替换、IMP*存储){
@同步(类){
方法方法=类\ getInstanceMethod(类,选择器);
IMP original_IMP=NULL;
if(方法!=NULL){
const char*type=method\u getTypeEncoding(method);
IMP original_IMP=类_replaceMethod(类、选择器、替换、类型);
如果(原始值=空)
原始\u imp=方法\u getImplementation(方法);
if(原始输入!=NULL&&store!=NULL){
*存储=原始输入;
}
}
返回值(原始值=NULL);
}
}
+(空)荷载
{
静态IMP originalMethodImpl=NULL;
IMP customMethodImpl=IMP_实现与块(^(id self_uu){
NSString*descr=((NSString(*)(id,SEL))originalMethodImpl)(self_2;,@selector(description);
返回[NSString stringWithFormat:@“”,descr];
});
swizzle_实例_方法([self class]、@selector(description)、customMethodImpl和originalMethodImpl);
}
我想补充一点,这对于调试来说是很好的,对于构建优秀的框架来说也是很好的。唉,苹果似乎有不同的想法,使用方法swizzling可能会导致你的应用被排除在应用商店之外。如果你不是针对应用商店的,那么所有的力量都会给你。使用ObjC Category是可能的对于ex,您可以如下扩展NSString的hasPrefix方法:
-(BOOL)hasPrefixx:(NSString *)aString
{
NSLog(@"Checking has prefix");
return [self hasPrefix:aString];
}
如果你导入类别,你应该能够调用这个方法。但是他的意思是你在调用中改变了方法
顺便说一句,方法swizzling应该可以。解释一下。所有方法都阻塞了吗?@DanShelly,对不起,我不明白您的注释是您需要在完成之前阻塞执行线程的原始方法吗?您为什么不使用类别来扩展方法?为什么您不能子类化?根据我无法使用类别来重写e父类方法