Clang如何开启id<protocol>转类指针的不安全类型转换警告
Objective-C下让Clang对id到具体类的不安全隐式转换报警告
问题复现
重构代码时发现Clang不会对下述场景的不安全类型转换输出任何警告:
@protocol CommonProtocol <NSObject> - (void)common; @end @interface Foo : NSObject <CommonProtocol> - (void)foo; @end @interface Bar : NSObject <CommonProtocol> @end static id<CommonProtocol> getObject(void) { return [Bar new]; } Foo *casting = getObject(); // 此处无任何编译提示 [casting common]; [casting foo]; // 运行时直接崩溃:返回的是Bar实例,根本不响应`-foo`方法
逻辑上Foo *和id<CommonProtocol>根本不是可安全互换的类型:id<CommonProtocol>只要求指针指向的对象遵守CommonProtocol,既可能是Foo实例,也可能是Bar实例,直接赋值给Foo *类型的指针属于明显的向下不安全转换。但实测即使加了-Weverything参数,Clang也不会给出任何提示——因为这类检查属于会打破大量旧OC代码兼容的严格校验项,即使开全量警告也默认关闭。
可行方案
1. 开启指定编译参数
添加Clang编译标识:
-Wobjc-implicit-downcast
开启后,所有从通用类型(id、id<Protocol>、父类指针)隐式转换为具体类/子类指针的操作,Clang都会抛出警告提示风险。如果确实需要做这类转换,手动写显式强转(Foo *)即可消除警告,相当于明确告知编译器你知晓转换的潜在风险。
如果使用的是Clang 13以下的老旧版本,没有上述参数,可以替换为-Wobjc-id-conversion达到基本一致的效果。
2. 调整类型声明(无需改编译配置)
如果不方便全局调整编译参数,直接把函数返回值里的id<Protocol>写法换成根类加协议限定的指针类型即可:
// 替换前:static id<CommonProtocol> getObject(void) static NSObject<CommonProtocol> *getObject(void) { return [Bar new]; }
NSObject<CommonProtocol>*属于明确的对象指针类型,不再是OC里有特殊兼容规则的id类型,修改后再把返回值隐式赋值给Foo *,Clang会直接触发默认开启的-Wincompatible-pointer-types警告,不需要额外加任何编译参数。
内容的提问来源于stack exchange,提问作者Kam
相关产品推荐
相关产品推荐

