Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/98.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在方法中添加其他行为而不进行子类化_Ios_Objective C_Oop_Objective C Blocks - Fatal编程技术网

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”的机制扩展任何类(即使是没有实现文件的类)

  • 在Xcode中单击文件->新建->文件(命令+n)
  • 从Cocoa Touch中选择Objective-C类别
  • 键入类别的名称,然后选择要在其上创建类别的类(我选择了UIButton)
  • 然后下一步创建
  • Xcode将创建两个文件,例如:
    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父类方法