iOS Reachability 有趣之处

最近使用xcode8的beta版跑项目代码静态文件分析的时候发现Reachability里面有提示内存问题,然后顺手就改了,改完真机run起来后马上就崩溃了,后来详细看了一下源码,发现这是个有趣的问题,猜想有可能是作者有意为之。

内存问题代码段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+ (Reachability *) reachabilityWithHostName: (NSString *) hostName {
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if (ref) {
Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease];
r.key = hostName;
return r;
}
return nil;
} // reachabilityWithHostName

上面的代码一看便知问题所在,ref的对象通过SCNetworkReachabilityCreateWithName创建,需要使用CFRelease释放,但作者没这么做,那为什么Reachability整体又没有问题呢?继续看其中initWithReachabilityRef函数。

initWithReachabilityRef

1
2
3
4
5
6
7
8
9
- (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref
{
self = [super init];
if (self != nil)
{
reachabilityRef = ref;
}
return self;
} // initWithReachabilityRef:

代码粗略看没什么问题,那有问题的只能是reachabilityRef这个属性咯?下面是reachabilityRef的申明。

reachabilityRef申明

1
2
3
4
5
@interface Reachability: NSObject {
@private
NSString *key_;
SCNetworkReachabilityRef reachabilityRef;
}

这样问题就比较清晰了,initWithReachabilityRef函数中作者对reachabilityRef的赋值没有调用CFReatin持有ref对象,而是直接赋值,不会让引用计数加1,所以导致ref创建后不能调用CFRelease释放ref。

这种写法可能是作者有意为之,但总觉得挺坑的,至少新版xcode都不认同这种写法,[哭笑][哭笑][哭笑]。