【大娃一点技术】NSProxy

作者: 飞翔的大娃 | 来源:发表于2017-07-14 13:39 被阅读68次

    前言的前言

    经过一些思考和反省,感觉平时只记录东西在脑中,年纪大了,淡忘了很多。so,准备以此为平台记录下,造福自己,当然如果有读者能够获益,那也是极好的。

    文笔不好,也不喜欢长篇大论。讲些别人没表述的以及自己的一些领悟。

    本人技术能力一般,可能存在理解上的错误,所以欢迎大家留言指正。


    本文前言

    NSProxy,一个特殊的存在,所谓的抽象类。一班人用的很少,三年二班的其实用的也不多。

    一个概念性的类,近期想解决一个iPhone、iPad的适配问题,突然回想起了它。简单介绍下,合作的同学做了2个view,一个4iPhone、一个4iPad,他们使用了同样的function、property,就是类名不一样,而且2者也没有继承关系。(内心的os就是:你这个坑我跳的爽)。

    思路是利用一个对象,在不同的环境下指向到不同的view。如果更进一步,我想到了NSProxy。当然最终是实现了的,本文的详细内容是在事后重新梳理的实现方式。


    一、概述

    从各种教程上大家可以理解NSProxy有以下特点:

    1. 不继承NSObject,即不是NSObject。
    2. 遵循了NSObject协议。(和上面一点的区别自己领悟,继承和协议)。
    3. 解决多继承问题。
    4. 解决弱引用问题。
    5. 未完待续,可能存在我还不了解的点。

    二、代码示例

    一个可用的weakProxy,用以解决NSTimer和controller之间的循环引用问题。

    声明

    @interface BWeakProxy : NSProxy
    
    + (nonnull instancetype)proxyWithTargetObject:(nullable id)targetObject;
    
    - (void)setTargetObject:(nullable id)targetObject;
    
    - (nullable id)targetObject;
    
    @end
    

    实现

    @implementation BWeakProxy {
        __weak id _targetObject;
    }
    
    + (nonnull instancetype)proxyWithTargetObject:(nullable id)targetObject {
        id proxy = [self alloc];
        [proxy setTargetObject:targetObject];
        return proxy;
    }
    
    - (void)setTargetObject:(nullable id)targetObject {
        _targetObject = targetObject;
    }
    
    - (nullable id)targetObject {
        return _targetObject;
    }
    
    - (void)forwardInvocation:(NSInvocation *)invocation {
        if ([_targetObject respondsToSelector:invocation.selector]) {
            [invocation invokeWithTarget:_targetObject];
        }
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
        NSMethodSignature *signature = nil;
        if ([_targetObject respondsToSelector:sel]) {
            signature = [_targetObject methodSignatureForSelector:sel];
        } else {
            // 动态造一个 void object selector arg 函数签名。
            // 目的是返回有效signature,不要因为找不到而crash
            signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
        }
    
        return signature;
    }
    @end
    
    

    调用

    [NSTimer scheduledTimerWithTimeInterval:3.0f target:[BWeakProxy proxyWithTargetObject:self] selector:@selector(timerInvoke) userInfo:nil repeats:YES];
    

    三、要点

    没有太多分析,只想说说最重要的部分。

    1. methodSignatureForSelector的实现细节

    • 有2步,首先判断了被代理对象是否含有相关的selector。如果有,你自然懂的。

    • 如果没有,那么问题来了。一般我们会返回nil,而这个时候系统会出现doesnotrecognizeselector的相关错误。经过猜想,感觉苹果的初衷是,有实际方法就调用,没有的话就抛异常,目的是让用户明确的调用。

    • 但是一般我们使用代理,希望温柔点。有就执行,如果没有,就不执行,别让我crash了。所以在这里,我手动建立了一个

    signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    

    这个signature是会被传到后面的forwardInvocationinvocation中。不过forwardInvocation的处理我们关注的还是selector,所以这个临时signature也没什么作用了,就是不要在意了。

    2. weak target

    __weak id _targetObject;
    
    • 这里必须是weak,否则就会循环引用了。
    • 一般同学习惯使用weak的property。不过我个人更倾向使用成员变量,理由么,我总希望暴露的东西越少越好。

    四、其他

    文章写的很潦草,如果你感兴趣却有疑问,可以随意留言。我会尽快完善。

    至于NSProxy的其他应用比如多继承,暂时没有实现,看以后的机缘了。

    目前没有github,之后应该会完整工程放上去。

    感谢你的阅读!

    相关文章

      网友评论

        本文标题:【大娃一点技术】NSProxy

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