2013-12-18 5 views
5

Я использую класс Reachabiliry от Apple в моем недуговом проекте. И когда я запускаю его с помощью инструментов для поиска утечек памяти, он ссылается на метод Reachability. Вот в чем проблема:Явная утечка памяти Apple

+ (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; 
} 

Просочившиеся объекты достижимы и возвращаются. Я понимаю, что 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 reachabilityForInternetConnection] startNotifier]; 

И не назначить его на любой объект, просто использовать эту линию. Я пытался изменить это вызывает что-то вроде:

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

Но после того, как этот анализатор сказал мне «слишком много autorelease».

ответ

4

Если значение returnValue равно NULL, объект утечки просочился, вы должны его отпустить в этом случае. Кроме того, по какао именования (https://developer.apple.com/library/ios/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1) вы должны вернуть autoreleased объекта:

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

Или переименовать метод для запуска, например, из нового: newReachabilityWithAddress или что-то вроде этого, если вы не хотите, чтобы вернуть autoreleased объекта.

Попробуйте запустить статический анализатор в Xcode, это может помочь выявить проблемы.

+0

и анализатор и дуга также полагаются на соглашения об именах –

+0

Daij-Djan, не могли бы вы объяснить? – Maria

+0

Кроме того, я только что обновил вопрос. – Maria

0

Правильное исправление для кода заключается в следующем в CFRelease in dealloc.

посмотрите на тело кода ниже. Аналогичному телу необходимо также обратиться к достижимости с кодомHostName.

+ (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; 
} 
5

Я думаю, что лучше сделать это в следующий путь:

+ (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; 
} 
8

@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

последней достижимости.m, кажется, требуется ARC, мое приложение не использует его.

Я просто включил его за это:

  1. идти к цели \ строить фазы \ компилировать Sources

  2. найти достижимости и дважды щелкните на нем

  3. добавить -fobjc-дуга

память утечка исчезла

1

Решение с включенным ARC Reachability класс.

  1. Добавить CFAutorelease(ref) под номером строки.
  2. Удалите 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

+ (instancetype)reachabilityWithHostname:(NSString*)hostname { 
    SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]); 
    if (ref) { 
     id reachability = [[self alloc] initWithReachabilityRef:ref]; 
     CFAutorelease(ref); 
     return reachability; 
    } 

    return nil; 
} 
Смежные вопросы