0

我关注这篇文章是为了更好地理解方法混合的工作原理。我有这样的主视图控制器(这是一个新项目):

#import "GLViewController.h"
#import <objc/runtime.h>

@implementation UIViewController (Tracking)

+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    Class class = [UIViewController class];

    SEL originalSelector = @selector(viewWillAppear:);
    SEL swizzledSelector = @selector(xxx_viewWillAppear:);

    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didAddMethod =
    class_addMethod(class,
                    originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));

    if (didAddMethod) {
        class_replaceMethod(class,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
});
}

#pragma mark - Method Swizzling

- (void)xxx_viewWillAppear:(BOOL)animated {
[self xxx_viewWillAppear:animated];
NSLog(@"viewWillAppear: %@", self);
}

@end


@implementation GLViewController

-(void)viewWillAppear:(BOOL)animated
{
  NSLog(@"glviewappear");
}

 - (void)viewDidLoad
{
    [super viewDidLoad];

}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

如果我运行它,它会打印 glviewappear,如果我删除

-(void)viewWillAppear:(BOOL)animated
{
  NSLog(@"glviewappear");
}

然后它打印 viewWillAppear: <GLViewController: 0x9d11a90>。我的项目需要能够使用这两种方法。有没有办法做到这一点?

4

1 回答 1

5

有一个简单的原因。您没有调用 UIViewController 实现,因为您没有调用[super viewWillAppear:animated].

做就是了:

-(void)viewWillAppear:(BOOL)animated
{
  [super viewWillAppear:animated];
  NSLog(@"glviewappear");
}

这里有更详细的解释

Objective C 类中的每个方法只不过是一个简单的函数,通过保存在调度表中的指针来引用:键是选择器,它们的关联值是指向每个方法实现的指针(IMP)。

swizzle 时,您只需交换调度表中的两个指针,以便交换引用的函数。由于调度表是附加到类的,swizzling发生在您执行它的类中,而不发生在子类中。

在您的情况下,有 3 个不同的函数在起作用: UIViewController 在调度表中有指向以下函数的指针。这些函数在运行时通过 swizzling 进行交换。

  • viewWillAppear:(现在指向xxx_viewWillAppear:实施)
  • xxx_viewWillAppear:(现在指向viewWillAppear:实施)

GLViewController 有另一个指针,指向它自己的viewWillAppear:.

如果您不调用super,则不会访问UIViewController该类的调度表,因此您根本不会调用实现。

当您删除 viewWillAppear: 方法时,显然它可以工作,因为超级实现会自动调用。

于 2014-05-19T23:39:58.023 回答