2013-12-18 13 views
5

Używam klasy Reachabiliry Apple w moim projekcie non-arc. A kiedy uruchomię go z instrumentami, aby znaleźć wycieki pamięci, to odwołuje się do metody osiągalności. Oto problem:Nieszczelność pamięci osiągalnej 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; 
} 

Występujące przecieki są osiągalne i zwracane. Rozumiem, że SCNetworkReachabilityCreateWithAddress tworzy nową instancję i muszę ją wydelegować, ale dzieje się to dokładnie w dealloc!

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

Co mogę zrobić, aby uniknąć wycieku pamięci?

UPD: Może problem polega na tym, w jaki sposób uzyskuje się możliwość osiągnięcia dostępności? Używam tej metody:

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

    return [self reachabilityWithAddress:&zeroAddress]; 
} 

Potem nazwie osiągalności tak:

[[Reachability reachabilityForInternetConnection] startNotifier]; 

I nie przypisać go do dowolnego obiektu, wystarczy użyć tej linii. Próbowałem zmienić ten nazywa się coś takiego:

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

Ale po to analizator powiedział mi „zbyt wiele autorelease”.

Odpowiedz

4

Jeśli wartość zwracana jest równa NULL, obiekt osiągalności jest nieszczelny, należy zwolnić go w tym przypadku. Również przez Cocoa nazewnictwo (https://developer.apple.com/library/ios/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1) musi powrócić autoreleased obiektu:

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

lub zmienić nazwę metody, aby rozpocząć od nowa na przykład: newReachabilityWithAddress czy coś takiego, jeśli nie chcą zwrócić autoreleased obiekt.

Spróbuj uruchomić analizator statyczny w Xcode, może pomóc wykryć problemy.

+0

i analizator i łuk również polegają na konwencjach nazewnictwa –

+0

Daij-Djan, czy mógłbyś wyjaśnić? – Maria

+0

Ponadto właśnie zaktualizowałem pytanie. – Maria

0

Prawa poprawka dla kodu jest następująca oprócz CFRelease w dealloc.

spójrz na treść poniższego kodu. Podobny organizm musi również wejść w kod osiągalności WithHostName.

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

myślę, lepiej zrobić to następny sposób:

+ (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 odpowiedź pracował dla mnie, ale jeśli chcesz uproszczoną wersję, użyj

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

najnowsze osiągalności.m wydaje się wymagać ARC, moja aplikacja go nie używa.

właśnie włączył do niego:

  1. iść do celów \ zbudować fazy \ skompilować źródłom

  2. find osiągalność i podwójne kliknięcie na nim

  3. dodać -fobjc łukowego

wyciek pamięci zniknął teraz

1

Rozwiązanie z włączoną opcją ARC Reachability.

  1. Dodaj CFAutorelease(ref) pod wierszem wydania.
  2. usunąć kod CFRelease(self.reachabilityRef) z dealloc

Aktualizowane dealloc

- (void)dealloc { 
    [self stopNotifier]; 

    self.reachableBlock   = nil; 
    self.unreachableBlock  = nil; 
    self.reachabilityBlock  = nil; 
    self.reachabilitySerialQueue = nil; 
} 

Aktualizowane 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; 
} 

Updated 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; 
}