美文网首页iOS开发iOS plus
OC 中如何做到分类方法不覆盖原方法

OC 中如何做到分类方法不覆盖原方法

作者: Seimda | 来源:发表于2017-06-15 22:34 被阅读471次

    今天在用 ShareSDK 做第三方登录的时候,发现使用旧版 SDK 时是在 AppDelegate.m 文件里手动实现 2 个处理客户端返回消息的回调方法,如下图

    而新版 SDK 却不需要。那么问题来了,新版是在哪里实现处理客户端返回消息的回调方法?

    要知道,处理回跳必须需要实现以下方法

    iOS 9 以下用这个

    -(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation

    iOS 9 及以上用这个

    -(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options

    我猜想 ShareSDK 是用 AppDelegate 的分类实现了方法,但一般情况下,在OC中只要分类实现了方法,那么类中的原来实现方法就不会被调用。 而现在这个方法我们可以自定义实现,且不影响第三方客户端回跳,怎么做???

    其实要做到分类方法不覆盖原方法需要用的 OC 的 Runtime ,来测试一下

    在 AppDelegate.m 中实现 applicationDidBecomeActive:

    - (void)applicationDidBecomeActive:(UIApplication *)application {
        NSLog(@"applicationDidBecomeActive");
    }
    

    再创建一个 AppDelegate 的分类,实现applicationDidBecomeActive:

    - (void)applicationDidBecomeActive:(UIApplication *)application {
        NSLog(@"applicationDidBecomeActive--分类");
        Class currentClass = [AppDelegate class];
        if (currentClass) {
            unsigned int methodCount;
            Method *methodList = class_copyMethodList(currentClass, &methodCount);
            IMP lastImp = NULL;
            SEL lastSel = NULL;
            for (NSInteger i = 0; i < methodCount; i++) {
                Method method = methodList[i];
                NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))
                                                          encoding:NSUTF8StringEncoding];
                if ([@"applicationDidBecomeActive:" isEqualToString:methodName]) {
                    lastImp = method_getImplementation(method);
                    lastSel = method_getName(method);
                }
            }
            typedef void (*fn)(id,SEL,id);
            if (lastImp != NULL) {
                fn f = (fn)lastImp;
                f(self,lastSel,application);
            }
            free(methodList);
        }
    }
    

    打印结果

    2017-06-15 21:55:45.709 demo[807:25011] applicationDidBecomeActive--分类
    2017-06-15 21:55:45.709 demo[807:25011] applicationDidBecomeActive
    

    这样,就可以同时调用分类和原类的方法了,不知道 ShareSDK 是不是这样的思路

    参考

    对OC中Category 的理解,以及方法覆盖的解决办法

    相关文章

      网友评论

      • 承宇:你好,我想写个方法给其他人调用的话。要是别人把Appdelegate这个文件名称改了,我的Appdelegate分类就不好用了。针对这个问题的话,ShareSDK是如何处理的呢?
      • 谦言忘语:试过下,楼主的方法确实可以。但是如果多个分类同时覆盖了原方法,那么只会有一个分类的方法和原方法被调用,这个问题不好解决啊
        Seimda:不知道你注意到 lastImp 变量没,示例代码中, lastImp 只是取了这个方法的最后一个实现,即原方法的实现。同理,你可以取到其他任意多个分类中方法的实现,然后调用就可以了。不过,要注意各分类方法调用的先后顺序

      本文标题:OC 中如何做到分类方法不覆盖原方法

      本文链接:https://www.haomeiwen.com/subject/cqnuqxtx.html