美文网首页
JSPatch新增方法

JSPatch新增方法

作者: 千若逸 | 来源:发表于2016-04-12 16:13 被阅读934次

    这几天遇到一个JSPatch的一个小坑,在OC调用新增方法时出现Crash,但是看Wiki上面的说明,还是有点疑惑,原文是这么写的:"可以给一个类随意添加 OC 未定义的方法,但所有的参数类型都是 id"。

    做了一个简单的复现demo,核心代码如下:

    - (int)testImp
    {
        SEL selector = NSSelectorFromString(strMethod);
        IMP imp = [self methodForSelector:selector];
        int (*func)(id, SEL) = (typeof(func))imp; // void *
        int value = func(self, selector);
        return value;
    }
    

    这个testImp方法是在OC里面的viewDidLoad方法中调用的,而strMethod也是动态赋值的,如果它是新增方法的话,在main.js里增加它的实现,func调用就会出错。

    然后我做了另一个测试,在main.js里直接调用这个新增方法,调用与返回值都是正常的。说明只有在OC里调用新增方法才会遇到问题。

    本来我以为在OC里调用新增方法出错,是因为在调用它的时候class_addMethod过程还没有发生,于是我在js里把这个新增方法的位置放在viewDidLoad之前,并没有卵用,现在想来太天真。

    想过自己要实现class_addMethod,但是这就意味着会与JSPatch自带的class_addMethod冲突,并不靠谱。突然想到之前唯敬之前发的文章JSPatch defineProtocol部分实现详解 - 简书,再仔细一读,发现答案就在这篇文章里面。

    与作者交流,发现了另外一种产生此问题的Case:在OC里调用一个有声明无实现的方法,尽管在js里新增它的实现,依然会产生Crash。

    我遇到的这个问题与他遇到的问题类似,只不过它的原因是参数为非id类型,我的是返回值为非id类型。通用的原因可以这样描述:希望新增的方法是一个含有非id类型参数或非id类型返回值的方法,而JSPatch最终添加的新方法的参数或返回值都是id,在OC调用时找不到它想要的方法。

    解决方法是用文中的defineProtocol来指定新增方法的参数类型与返回值类型,确保生成正确的type encode。我确定自己以前被标题中的defineProtocol欺骗了,以为只能用于新增协议方法,实际上也可以用于我这种新增方法的需求。只不过因为直接修改defineClass牵涉过大,所以才在defineProtocol中实现。

    比如我这种情况就可以这样新增方法:

    defineProtocol("testProtocol",{
    newMethod:{
    returnType:"int",
        },
        })
    

    有非id类型的入参就这样写:

    defineProtocol("testProtocol",{
    newMethod:{
    paramsType:"BOOL , float , CGFloat",
    returnType:"int",
        },
        })
    

    接着在defineClass中设置遵守testProtocol协议:

    defineClass('TestViewController : UIViewController <testProtocol>' , {
    })
    

    然后你就可以愉快地在OC中调用这个newMethod了。

    相关文章

      网友评论

          本文标题:JSPatch新增方法

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