onePatch 修复指南

方法名约定

所有方法名中的“:”(冒号)需要用“”(下划线)代替。方法名中的每个“”(下划线)用“__”(两个下划线)代替。

示例:

@interface TestView : UIView
- (void)ig_setTitle:(NSString *) forState:(NSInteger)state;
@end

[testView ig_setTitle:'title' forState:1];

对于以上oc方法,需要替换为:

// ig后面本来是一个下划线,需要写成两个,setTitle后面的冒号,用下划线代替
testView.ig__setTitle_forState('title', 1);

修复实例方法

class OPViewController { // 需要修复的方法所在的类名
    test(param1, param2) { // 参数会自动带有两个隐藏参数:self和_cmd
        // 可以使用super.xxx()调用父类的方法
        // something to do
    }
    anotherMethod() {
        // ...
    }
}

修复类方法

class OPViewController { // 需要修复的方法所在的类名
    static test(param1, param2) { // 参数会自动带有两个隐藏参数:self和_cmd
        // 可以使用super.xxx()调用父类的方法
        // something to do
    }
    static anotherMethod() {
        // ...
    }
}

类方法和实例方法唯一的区别是:方法名前面是否带有static关键字。带static的为类方法。

在一个补丁文件中,允许同时写多个类,但不能在class中嵌套class。

在一个class中,允许同时修复多个方法。

调用原来的方法实现

当您在修复某个方法时,您可以用origin__+方法名()调用原来的方法。注意origin后面是两条下划线。

这个功能非常有用,假设您要修复的方法中,有很多行代码,这些代码中,大部分是没问题的,只有其中一两行有问题, 您并不需要将整个方法用热修复代码重写一遍,只需要先调用原来的方法,再把有问题的代码纠正一下即可,前提是这个方法不会crash。

代码示例

@implementation OPViewController
    viewDidLoad() {
        // 假设这里有很多代码...
        self.title = @"错误的标题";
        // 这里也有很多业务代码...
    }
}
@end

对于以上的viewDidLoad方法,热修补丁代码的推荐写法为:

class OPViewController {
    viewDidLoad() {
        self.origin__viewDidLoad(); // 调用原来的viewDidLoad()方法 注意:origin后面是两条`下划线`
        self.setTitle('正确的标题'); // 修复代码
    }
}

输出日志

class OPViewController {
    test(param1, param2) { // 参数会自动带有两个隐藏参数:self和_cmd
        // log(xxx)
        log('Hello World' + '!');
    }
}

weak与strong 指针

class OPViewController {
    test(param1, param2) {
        var weak_instance = __weak(param1);
        // ...

        var strong_instance = __strong(param2);
        // ...
    }
}

获得一个Class指针

// 返回Class指针,等价于:Class uiView = [UIView class];
const UIView = require('UIView');

Class指针常用于调用类方法,或者其他需要用到Class指针的场景,比如isKindOfClass()中的参数。

调用类方法或实例方法

// 调用类方法 require('类名').方法名(参数1, 参数2...)
// 方法调用支持链式调用:xxx.xxx().xxx()...
const instance = require('OPTestCallMethod').alloc().init();
instance.isKindOfClass(require('OPTestCallMethod')); /// true

// 调用实例方法 实例.方法名(实例变量, 方法名, 参数1, 参数2...)
// 这里需要注意方法名中的冒号需要被替换为下划线
instance.testWithArg1_arg2(100, 'Hello World');

调用实例的父类的方法

class OPViewController {
    test(param1, param2) {
        super.test(param1, param2); // 直接使用super关键字
    }
}

设置或获取实例的属性值-成员变量

// 设置实例的属性值
instance.setTitle('OPViewController');
// 获取实例的属性值
const title = instance.title(); // return 'OPViewController'

简而言之,获取/设置属性,其实就是调用setter和getter方法。

如果发现有不能正常使用的情况,或者需要设置或获取没有setter和getter的属性值,比如:

@interface OPViewController() {
    NSString *_name;
}
@end

上面的_name属性没有setter和getter,所以需要使用setInstanceProperty和getInstanceProperty来设置或者获取属性值: 代码示例:

// 设置实例的属性值
setInstanceProperty(self, '_name', 'Hello world');
// 获取实例的属性值
const name = getInstanceProperty(self, '_name'); // name is 'Hello world'

创建 block

使用 block 函数来创建 Native block 函数。 block 函数第一个参数为:函数签名编码,第一个字符为返回参数类型编码,后面跟着入参类型编码。参数类型对应的编码字符参考 TypeEncoding。

block 函数第二个参数为回调js函数,回调函数参数为 native block 入参变量。

class OPTestBlock {
    testReturnBlock(blk) {

        // 函数签名编码:第一个字符为返回参数类型编码,后面跟着入参类型编码。
            let blk_obj = block("vcislqCISLQfdB@#", function(c, i, s, l, q, C, I, S, L, Q, f, d, B, anObject, classParm) {
            log(c);
            log('i=' + i);
            log('s=' + s);
            log('l=' + l);
            log('q=' + q);
            log('C=' + C);
            log('I=' + I);
            log('S=' + S);
            log('L=' + L);
            log('Q=' + Q);
            log('f=' + f);
            log('d=' + d);
            log('B=' + B);
            log(anObject);
            var isOPTestClass = self.isKindOfClass(classParm);
            log('self class is OPTestClass : ' + isOPTestClass);
        });
        return blk_obj;
    }
}

nil的使用

函数参数、属性读写、函数返回值均支持nil的转换。在JS代码中undefined等同于nil,更推荐使用全局符号nil来表示:

class OPTestNilTransform {
    test() {
        self.testNil(nil);
        self.setState(nil);
        return nil;
    }
}
Copyright © 2013-2023 Tencent Cloud. all right reserved,powered by GitbookUpdate Time 2023-08-31 14:46:07

results matching ""

    No results matching ""