0

我需要向需要扩展的方法添加额外的行为,即实现看起来像的方法

- (void)extendMethod:(SEL)selector forClass:(Class)class withCompletionBlock:(void (^)(void))completionBlock;

因此,每次Class实例调用带有SEL选择器的方法时,都应该调用我的完成块

我尝试过方法调配,但遇到了一些问题:我希望调用原始方法实现。

我需要的与子类化非常相似,但这应该在没有子类化的情况下实现。

更新:

例如,我有UIViewControllernamed的子类MyViewControllerMyViewController- (void)viewDidLoad方法。我在应用程序的某个地方调用方法

[methodExtender extendMethod:@selector(viewDidLoad)
                    forClass:[MyViewController class]
         withCompletionBlock:^{
             NSLog(@"view did load called");
         }];

因此,在 MyViewController 的每个实例的 viewDidLoad 方法之后,我调用了完成块。

4

4 回答 4

1

我不确定你想如何使用选择器,但你可以尝试通过使用 Objective-C 中称为“类别”的机制来扩展任何类(甚至是那些你没有实现文件的类)。

  1. 从 Xcode 点击 File->New->File (command+n)
  2. 从 Cocoa Touch 中选择 Objective-C 类别
  3. 输入您的类别名称并选择您要创建类别的类别(我选择了 UIButton)
  4. 然后下一步并创建。

例如,Xcode 将创建两个文件:UIButton+extendMethod.h 在头文件中声明您的方法并在 *.m 文件中实现它。

使用

如果您想在 *.h 文件导入中使用您的视图控制器 #import "UIButton+extendMethod.h"

然后你可以这样调用你的方法:

UIButton *button = [[UIButton alloc] init]; [button extendMethod:@selector(yourMethod:)];

于 2013-05-10T14:51:38.990 回答
0

使用 ObjC 类别是可能的。例如,您可以扩展 NSString 的 hasPrefix 方法,如下所示,

-(BOOL)hasPrefixx:(NSString *)aString
{
    NSLog(@"Checking has prefix");
    return [self hasPrefix:aString];

}

如果您导入类别,您应该可以调用此方法。但是他的意思是您可以更改通话中的方法。

顺便说一句,Method swizzling 应该可以工作。这里有点解释。

于 2013-05-10T15:01:36.430 回答
0

没有子类化就没有办法(不再)模拟继承。曾经有 Posing,剩下的就是方法混合(虽然不像 pose 那样优雅)。这是一种在能够调用原始实现的同时正确进行方法调配的方法。

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

我可能会补充一点,这对于调试非常有用,而且我认为它对于构建优秀的框架非常有用。唉,Apple 似乎有不同的想法,使用方法调配可能会导致您的应用程序被排除在 App Store 之外。如果您的目标不是应用商店,那么您将拥有所有的力量。

于 2013-05-10T15:00:24.113 回答
0

Swizzling 确实允许您调用原始实现,尽管它有点令人困惑。因为实现是在 swizzling 之后交换的,所以您可以使用 swizzled 方法的选择器调用原始实现:

- (void)mySwizzledImplementation {
    // do stuff
    // now call original implementation (using swizzled selector!)
    [self mySwizzledImplementation];
    // do more stuff
}

另见http://cocoadev.com/wiki/MethodSwizzling

于 2013-05-10T14:56:56.473 回答