【问题标题】:ios swizzle better understandingios swizzle 更好理解
【发布时间】:2019-04-10 20:04:10
【问题描述】:

我有一个带有此代码的 UIViewController:

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

然后我有一个带有 UIViewController 类别的框架,它以这种方式运行:

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        SEL viewWillAppearSelector = @selector(viewDidAppear:);
        SEL viewWillAppearLoggerSelector = @selector(logged_viewDidAppear:);
        Method originalMethod = class_getInstanceMethod(self, viewWillAppearSelector);
        Method extendedMethod = class_getInstanceMethod(self, viewWillAppearLoggerSelector);
        method_exchangeImplementations(originalMethod, extendedMethod);

    });
}

- (void)logged_viewDidAppear:(BOOL)animated
{
    [self logged_viewDidAppear:animated];

    NSLog(@"SWIZZLED");
}

输出是 SWIZZLED,然后是 CLASIC。

现在我的问题是:如果在我的视图控制器中我评论了 [super viewDidAppear:animated];然后不再调用 swizzled 方法;这是为什么?我理解了大部分方面,但似乎这一方面不知何故滑倒了。

- (void)viewDidAppear:(BOOL)animated
{
    // we comment this and this will trigger the swizzled method not being called anymore
    //[super viewDidAppear:animated];
    NSLog(@"CLASIC");
}

// ========================

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        SEL viewWillAppearSelector = @selector(viewDidAppear:);
        SEL viewWillAppearLoggerSelector = @selector(logged_viewDidAppear:);
        Method originalMethod = class_getInstanceMethod(self, viewWillAppearSelector);
        Method extendedMethod = class_getInstanceMethod(self, viewWillAppearLoggerSelector);
        method_exchangeImplementations(originalMethod, extendedMethod);

    });
}

- (void)logged_viewDidAppear:(BOOL)animated
{
    [self logged_viewDidAppear:animated];

    NSLog(@"SWIZZLED");
}

【问题讨论】:

  • 您注释掉了方法调用并且不再调用该方法 - 您还期望什么?
  • @mag_zbc 我评论了super调用,替换当前的swizzled方法和super有什么关系?

标签: ios objective-c swizzling method-swizzling


【解决方案1】:

方法调配用于在运行时用自定义方法覆盖原始方法。因此,您几乎可以将任何方法(包括 Apple 实现的私有方法)与您编写的自定义方法进行交换。

所以想象有一个名为Parent 的类和一个名为A 的方法,你在它被调用之前的某个地方与B 交换它,就像在load 方法中一样。从现在开始,'Parent' 之外的每个子类都将使用 B,但原始的 'A' 方法除外。但是,如果您在子类中覆盖 A 怎么办?作为继承定义,对象将调用它们的自己的方法,如果它们没有实现它,它们会使用它们的超类的方法。那么如果你想要parent implementation 怎么办?这就是super 的用武之地。

结论

  • 如果你重写一个方法,超类(或超类中的自定义交换方法)方法将不会被调用
  • 如果你想要父实现,你必须使用 super 关键字来访问它

在这个问题的情况下:

  • 在不调用 super 的情况下覆盖子类中的方法意味着您只需覆盖 swizzled 的方法,它不会被调用。

希望对你有帮助

【讨论】:

  • 我想我明白了...我在继承 UIViewController 的 VC1 中,但我只替换了所有 UIViewController 中的 viewDidAppear,但在 VC1 中它覆盖了使我的 swizzling 不起作用的方法,除非我调用 super ,对吗?
  • 是的,您使用的方法在UIViewController(父级)中;)
  • 非常感谢...现在说得通了 :) 但是有没有办法确保在子类中我的 swizzle 方法会被调用,即使 super 没有被调用? :)
  • @Catalin 可以在objc_getClassList 的输出中调配作为 UIViewController 子类的所有类。但是这样做有一些极端情况。
  • 谢谢@Mats 我差点忘了??‍♂️
猜你喜欢
  • 2016-04-09
  • 2018-11-04
  • 1970-01-01
  • 1970-01-01
  • 2012-07-08
  • 2021-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多