简体   繁体   English

方法涡流无法正确点火?

[英]Method Swizzling not firing correctly?

I am following this article to better understand how method swizzling works. 我正在关注本文,以更好地了解方法混乱的工作方式。 I have my main view controller (this is a new project) like this: 我有这样的主视图控制器(这是一个新项目):

#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

If I run this, then it prints glviewappear, and if I remove 如果运行此命令,则将打印glviewappear,如果删除

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

then it prints viewWillAppear: <GLViewController: 0x9d11a90> . 然后它会打印viewWillAppear: <GLViewController: 0x9d11a90> My project needs to be able to fire on both of these methods. 我的项目需要能够同时使用这两种方法。 Is there a way to do this? 有没有办法做到这一点?

There is a simple reason. 有一个简单的原因。 You are not calling the UIViewController implementation since you are not calling [super viewWillAppear:animated] . 您没有在调用UIViewController实现,因为您没有在调用[super viewWillAppear:animated]

Just do: 做就是了:

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

Here is a more detailed explanation 这是更详细的说明

Each method in an Objective C class is nothing more than a simple function, referenced through a pointer saved in a dispatch table: the keys are the selectors, and their associated values are the pointers to each method implementation (the IMP ). Objective C类中的每个方法无非是一个简单的函数,通过保存在调度表中的指针进行引用:键是选择器,它们的关联值是每个方法实现( IMP )的指针。

When you swizzle, you just swap two pointers in the dispatch table, in order to swap the referenced functions. 当您烦恼时,只需交换调度表中的两个指针,即可交换引用的函数。 Since the dispatch table is attached to the class, swizzling happens only in the class on which you perform it, and not in the subclasses. 由于分派表已附加到该类,因此在执行它的类中发生混乱,而在子类中则不会发生混乱。

In your case, there are 3 different functions in play: UIViewController has the pointers to the following functions in the dispatch table. 在您的情况下,有3个不同的函数在起作用:UIViewController在分配表中具有指向以下函数的指针。 These functions get swapped at runtime through swizzling. 这些功能在运行时通过交换被交换。

  • viewWillAppear: (now pointing to xxx_viewWillAppear: implementation) viewWillAppear:现在指向xxx_viewWillAppear:实现)
  • xxx_viewWillAppear: (now pointing to viewWillAppear: implementation) xxx_viewWillAppear:现在指向viewWillAppear:实现)

GLViewController has another pointer, to its own implementation of viewWillAppear: . GLViewController还有另一个指针,指向它自己的viewWillAppear:的实现。

If you don't call super , you are not accessing the dispatch table of the UIViewController class, so you are not invoking the implementation at all. 如果不调用super ,则不会访问UIViewController类的调度表,因此根本就不会调用实现。

When you delete your viewWillAppear: method, obviously it works, since the super implementation gets automatically called. 当您删除viewWillAppear:方法时,显然可以使用,因为将自动调用超级实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM