-
Notifications
You must be signed in to change notification settings - Fork 2.2k
defineProtocol 使用文档
##问题
JSPatch 为一个类新增原本 OC 不存在的方法时,所有的参数类型都会定义为 id
类型,因为这种在 JS 里新增的方法一般不会在 OC 上调用,而是在 JS 上用,JS 可以认为一切变量都是对象,没有类型之分,所以全部定义为 id
类型。
但有种场景,需要让新增的方法参数类型不是 id
,那就是,在 OC 里 .h
文件定义了一个方法,这个方法里的参数和返回值不都是 id
类型,但是在 .m
文件中由于疏忽没有实现这个方法,导致其他地方调用这个方法时找不到这个方法造成 crash,要用 JSPatch 修复这样的 bug,就需要 JSPatch 可以动态添加指定参数类型的方法。对此可以用 defineProtocol()
接口定义参数类型,再在 defineClass()
中实现,就可以动态添加指定参数类型的方法了。
##API
defineProtocol(protocolDeclaration, instanceMethods , classMethods)
@param protocolDeclaration
:字符串,新增protocol的名字
@param instanceMethods
:字典,要添加到protocol的实例方法
@param classMethods
:字典,要添加到protocol的类方法
需要说明的是,在runtime中,协议一旦注册后就不可再修改,所以只能新增协议
- 在defineProtocol中
protocolDeclaration
参数输入协议名称 - 在defineProtocol中
instanceMethods
参数输入协议内实例方法的字典,以方法名为Key,Value也是一个字典,是实例方法的信息 - 在defineProtocol中
classMethods
参数输入协议内类方法的字典,以方法名为Key,Value也是一个字典,是类方法的信息
##示例
例如在 JPTestObject 对象中,.h
头文件定义了这样一个接口:
@interface JPTestObject
- (NSString *)stringWithRect:(CGRect)rect withNum:(float)num withArray:(NSArray *)arr;
@end
但在 .m
文件中没有实现这个接口,导致其他地方调用这个方法时 crash。对此可以用 JSPatch 修复,分两个步骤:
- 把这个方法定义成一个 protocol
- defineClass中实现这个 protocol
先看第一步,用 defineProtocol
接口把这个方法定义在一个新的 protocol 中:
defineProtocol('JPDemoProtocol',{
stringWithRect_withNum_withArray: {
paramsType:"CGRect, float, NSArray*",
returnType:"id",
},
}
接着第二步,在 defineClass 中实现这个方法:
defineClass('JPTestObject : NSObject <JPDemoProtocol>', {
stringWithRect_withNum_withArray:function(rect, num, arr){
//use rect/num/arr params here
return @"success";
},
}
大功告成,新增的方法参数类型会遵循 defineProtocol 里定义的类型,这时 OC 中再调用这个方法时就会调到在 JSPatch 新增的方法,让 APP 避免 crash。
更多使用 Case 参见 demo 工程里的 newProtocolTest.js
##更多参数类型
1.paramsType
和 returnType
中可以直接使用的参数类型位包括id
, BOOL
, int
, void
, char
, short
, unsigned short
, unsigned int
, long
, unsigned long
, long long
, float
, double
, CGFloat
, CGSize
, CGRect
, CGPoint
, CGSize
, CGVector
, UIEdgeInset
, NSInteger
, SEL
, block
。
2.参数是 OC 对象 NSObject
,比如NSArray
,CustomObject
,可以写作id
,也可以直接写类名,效果一样
paramsType:"id" paramsType:"CustomObject"
3.对于无法支持的参数,比如其他结构体,customStruct
,可以使用typeEncode
可选字段
testProtocolConstumStruct:{
paramsType:"unknown",
returnType:"int",
typeEncode:"i@:{CGVector=dd}"
},
4.当使用 typeEncode
时,类型字符串可以不必匹配任意填写,比如填写unknown,比如填写xxx,但是要求paramsType
的个数必须保证准确
5.自行填写的 typeEncode
,可以通过在项目中使用OC代码,在运行时通过系统获取
SEL selstr = NSSelectorFromString(@"testProtocolConstumStruct:");
Method method = class_getInstanceMethod(class, selstr);
const char* type = method_getTypeEncoding(logmanagermethod);