以下内容仅针对参数使用, 不包含方法检查。
以下内容仅针对OC, Swift不使用
#available
无法通过编译。说明部分均为推测, 没有翻看汇编结果进行完备论证, 抛砖引玉。
通常来说, 遇到API_AVAILABLE
限制版本的参数, 使用@available
就能完成判断。
然而云谲波诡, 是时候确确实实发生了通过版本检查却访问变量崩溃的情况, 令人匪夷所思。
比如下面这个在网络类型判断中使用参数:
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyNRNSA API_AVAILABLE(ios(14.1)) API_UNAVAILABLE(macos);
系统版本过低时, 直接调用会发生如下错误。
EXC_BAD_ACCESS (code=1, address=0x0)
最大的问题是, 即使通过了@available(iOS 14.1, *)
的检查, 仍有可能在少数诡异的设备上崩溃。虽然不可思议, 但这是事实。
解法
if (&CTRadioAccessTechnologyNRNSA) {
NSLog(@"1");
} else {
NSLog(@"0");
}
对这些版本限制相关参数添加动态检查。
胡扯
一下内容均为我的脑补与胡扯, 缺乏严谨论证, 有待熟手指点。
一开始假设问题存在时, 任何显式访问CTRadioAccessTechnologyNRNSA
的行为都会造成崩溃。
考虑到参数定义与内存对其。
CTRadioAccessTechnologyeHRPD
CTRadioAccessTechnologyLTE
CTRadioAccessTechnologyNRNSA
- 指针还原
指针地址间隔相同。手动计算CTRadioAccessTechnologyNRNSA
指针地址, 但是ARC下无法从内存地址直接还原NSString *
指针, 失败。
- memcmp
CTRadioAccessTechnologyNRNSA
内容为@"CTRadioAccessTechnologyNRNSA"
, 既然知道目标地址, 直接通过内存比较内容?
不知道具体实现, 只能说可以比较一部分, 但没什么卵用, 尝试不出精确校验的方法, 失败。
- 取地址
万念俱灰, 直接取地址。然鹅, 似乎可行。
盲猜是编译优化, 或者进程虚拟内存映射啥的, 反正似乎能用了。