Apple的可达性内存泄漏

时间:2013-12-18 07:27:51

标签: ios objective-c xcode memory-leaks reachability

我在非弧项目中使用了苹果的Reachabiliry课程。当我使用仪器运行以查找内存泄漏时,它会引用Reachability方法。这是问题所在:

+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
{
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);

    WReachability* returnValue = NULL;

    if (reachability != NULL)
    {
        returnValue = [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->reachabilityRef = reachability;
            returnValue->localWiFiRef = NO;
        }
    }
    return returnValue;
}

泄漏的对象是可达性和returnValue。 我知道SCNetworkReachabilityCreateWithAddress创建了一个新实例,我必须CFRelease它,但它发生在dealloc!

- (void)dealloc
{
    [self stopNotifier];
    if (reachabilityRef != NULL)
    {
        CFRelease(reachabilityRef);
    }
    [super dealloc];
}

那么我该怎样做才能避免内存泄漏?

UPD: 也许问题在于如何调用可达性?我用这个方法:

+ (instancetype)reachabilityForInternetConnection;
{
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    return [self reachabilityWithAddress:&zeroAddress];
}

然后我这样打电话给Reachability:

[[Reachability reachabilityForInternetConnection] startNotifier];

不要将它分配给任何对象,只需使用此行即可。 我试图将此调用更改为:

Reachability *reachability = [[Reachability reachabilityForInternetConnection] autorelease];
[reachability startNotifier];

但是在这个分析仪告诉我“太多自动释放”之后。

6 个答案:

答案 0 :(得分:9)

@Alexart回答对我有用,但如果你想要简化版,请使用

+(instancetype)reachabilityWithAddress:(void *)hostAddress
{
   SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
   if (ref)
   {
      id reachability = [[self alloc] initWithReachabilityRef:CFBridgingRetain((__bridge id)ref)];
      CFRelease(ref);
      return reachability;
   }
   return nil;

}

答案 1 :(得分:6)

我认为下一步做得更好:

+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
{
    Reachability* retVal = NULL;
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
    if(reachability!= NULL)
    {
        retVal= [[self alloc] init];
        if(retVal!= NULL)
        {
            retVal->reachabilityRef = reachability;
            retVal->localWiFiRef = NO;
        }
        else
        {
            CFRelease(reachability);
        }
    }
    return retVal;
}

答案 2 :(得分:4)

如果returnValue等于NULL可达性对象泄露,则应在此情况下释放它。同样通过Cocoa命名约定(https://developer.apple.com/library/ios/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1),您必须返回自动释放的对象:

+ (instancetype)reachabilityWithAddress:
{
    ...
     returnValue = [[[self alloc] init] autorelease];

或者,如果您不想返回自动释放的对象,请将该方法重命名为例如来自new:newReachabilityWithAddress或类似的内容。

尝试在Xcode中运行静态分析器,它可以帮助发现问题。

答案 3 :(得分:1)

最新的reachability.m似乎需要ARC,我的应用程序没有使用它。

我只是为它打开了它:

  1. 转到目标\构建阶段\编译源

  2. 找到可达性并双击它

  3. add -fobjc-arc

  4. 内存泄漏现在已经消失

答案 4 :(得分:1)

启用ARC的解决方案readPicture类。

  1. 在问题行下方添加Reachability
  2. CFAutorelease(ref)
  3. 中删除CFRelease(self.reachabilityRef)代码

    更新了dealloc

    dealloc

    更新了- (void)dealloc { [self stopNotifier]; self.reachableBlock = nil; self.unreachableBlock = nil; self.reachabilityBlock = nil; self.reachabilitySerialQueue = nil; }

    reachabilityWithAddress

    更新了+ (instancetype)reachabilityWithAddress:(void *)hostAddress { SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); if (ref) { id reachability = [[self alloc] initWithReachabilityRef:ref]; CFAutorelease(ref); return reachability; } return nil; }

    reachabilityWithHostname

答案 5 :(得分:0)

除了dealloc中的CFRelease之外,代码的正确修复如下。

查看下面代码的正文。类似的主体也需要进入reachabilityWithHostName代码。

+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress
{
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);

    Reachability* returnValue = NULL;

    if (reachability != NULL)
    {
        returnValue = [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->_reachabilityRef = CFRetain(reachability);
            returnValue->_alwaysReturnLocalWiFiStatus = NO;
        }
         CFRelease(reachability);
    }
    return returnValue;
}