2013-12-18 17 views
5

Tôi sử dụng lớp Reachabiliry của apple trong dự án phi hồ quang của tôi. Và khi tôi chạy nó với các công cụ để tìm rò rỉ bộ nhớ, nó đề cập đến phương pháp Reachability. Đây là vấn đề:Rò rỉ bộ nhớ khả năng truy cập của 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; 
} 

Đối tượng bị rò rỉ là khả năng tiếp cận và trả lạiValue. Tôi hiểu rằng SCNetworkReachabilityCreateWithAddress tạo một phiên bản mới và tôi phải CFRelease nó, nhưng nó xảy ra ngay trong dealloc!

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

Vậy tôi có thể làm gì để tránh rò rỉ bộ nhớ ở đây?

UPD: Có thể vấn đề là cách khả năng tiếp cận được gọi? Tôi sử dụng phương pháp này:

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

    return [self reachabilityWithAddress:&zeroAddress]; 
} 

Sau đó, tôi gọi reachability như thế này:

[[Reachability reachabilityForInternetConnection] startNotifier]; 

Và đừng gán nó vào bất kỳ đối tượng, chỉ cần sử dụng dòng này. Tôi đã cố gắng để thay đổi điều này các cuộc gọi đến một cái gì đó như:

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

Nhưng sau khi phân tích này nói với tôi "quá nhiều autorelease".

Trả lời

4

Nếu returnValue bằng với đối tượng reachability NULL bị rò rỉ, bạn nên giải phóng nó trong trường hợp này. Cũng bởi Cocoa quy ước đặt tên (https://developer.apple.com/library/ios/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1) bạn phải trả lại đối tượng autoreleased:

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

Hoặc đổi tên các phương pháp để bắt đầu ví dụ từ mới: newReachabilityWithAddress hoặc một cái gì đó như thế này nếu bạn không muốn trở về một đối tượng autoreleased.

Cố gắng chạy trình phân tích tĩnh trong Xcode, nó có thể giúp phát hiện sự cố.

+0

và phân tích & arc cũng dựa vào quy ước đặt tên –

+0

Daij-Djan, bạn có thể giải thích không? – Maria

+0

Ngoài ra, tôi vừa cập nhật câu hỏi. – Maria

0

Sửa lỗi đúng cho mã như sau ngoài CFRelease trong dealloc.

xem nội dung của mã bên dưới. Cơ thể tương tự cũng cần phải đi vào mã khả năng truy cậpWithói tên miền.

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

Tôi nghĩ tốt hơn để làm theo cách sau:

+ (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 câu trả lời làm việc cho tôi, nhưng nếu bạn muốn có một phiên bản đơn giản, sử dụng

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

khả năng hiển thị mới nhất.m có vẻ như yêu cầu ARC, ứng dụng của tôi không sử dụng nó.

Tôi chỉ bật nó lên cho nó:

  1. đi đến mục tiêu \ xây dựng giai đoạn \ biên dịch nguồn

  2. tìm reachability và kích đúp vào nó

  3. thêm -fobjc-arc

rò rỉ bộ nhớ đã biến mất

1

Giải pháp với ARC bật lớp Reachability.

  1. Thêm CFAutorelease(ref) bên dưới hàng phát hành.
  2. Di mã CFRelease(self.reachabilityRef) từ dealloc

Cập nhật dealloc

- (void)dealloc { 
    [self stopNotifier]; 

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

Cập nhật 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; 
} 

Cập nhật 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; 
}