Swift含Block方法的objc_method_description.types编码格式问询
Swift生成的Objective-C扩展方法类型编码解析问题
问题核心
Swift编译器为包含Block的异步方法生成的Objective-C方法编码,使用了官方ObjC类型编码文档未记载的语法,涉及的特殊字符包括*"、<、>*。
例如以下Swift方法:
func DebugLog2(message: String) async -> String
对应的方法编码为:
v32@0:8@"NSString"16@?<v@?@"NSString">24
NSMethodSignature兼容性问题
NSMethodSignature类无法兼容这类扩展编码,执行以下代码:
[NSMethodSignature signatureWithObjCTypes:"\"NSString\"16@?<v@?@\"NSString\">24"];
会触发报错:
'+[NSMethodSignature signatureWithObjCTypes:]: unsupported type encoding spec '"' in '"NSString"16@?<v@?@"NSString">24''
Swift代码库线索
查阅Swift代码库时,发现存在“extended method type encodings(扩展方法类型编码)”相关的测试代码,但未找到该编码的具体生成逻辑。
示例代码与输出
Swift示例代码
decodeProto() @objc class TestClass : NSObject { @objc func DebugLog(message: String) -> String { print(message) return message } @objc func DebugLog2(message: String) async -> String { do { try await Task.sleep(nanoseconds: 1_000_000_000) } catch {} print(message); return message; } } func decodeProto() { var methodCount : UInt32 = 1 let methodList = class_copyMethodList(TestClass.self, UnsafeMutablePointer(&methodCount))! for i in 0..<Int(methodCount) { let method = methodList[i]; let desc = method_getDescription(method); let name = desc.pointee.name! let types = String(validatingUTF8: desc.pointee.types!)! print("Selector: \(name) Description: \(types)") } }
运行输出
Selector: DebugLog2WithMessage:completionHandler: Description: v32@0:8@"NSString"16@?<v@?@"NSString">24 Selector: DebugLogWithMessage: Description: @24@0:8@16 Selector: init Description: @16@0:8
需求背景
需要通过解析方法编码计算栈帧的最大尺寸,该需求源于拦截objc_msgSend调用,在调用实际objc_msgSend前添加Objective-C异常处理,逻辑如下:
intercept_objc_msgSend (...) { @try { objc_msgSend (...); } @catch (NSException *ex) { handleException (ex); } }
由于无法用C创建通用拦截方法,故采用汇编实现。通用拦截代码需为原始参数(栈帧)分配空间并复制,因此需解析方法编码以确定每个参数的大小。只需获取最大尺寸而非精确值,累加所有参数所需空间即可,无需减去寄存器传递参数的尺寸。
内容的提问来源于stack exchange,提问作者Rolf Bjarne Kvinge
相关产品推荐
相关产品推荐

