2013-05-01 16 views
6

Używam NSInputstream & NSOutputstream do konfiguracji połączenia i wysyłania danych. Mój obiekt strumienia ma funkcję otwierania i zamykania strumienia. Używam następującego kodu:Wycieki pamięci w CFStreamCreatePairWithSocketToHost iOS

@interface Stream() 
{ 
    NSInputStream *inputStream; 
    NSOutputStream *outputStream; 
} 

-(id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     inputStream = nil; 
     outputStream = nil; 
    } 
    return self; 
} 

-(int)streamOpenWithIp:(NSString *)ip withPortNumber:(int)portNumber; 
{ 
     CFReadStreamRef readStream; 
     CFWriteStreamRef writeStream; 

     CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)ip, portNumber, &readStream, &writeStream); 

     if(readStream && writeStream) 
     { 
      //Setup inpustream 
      inputStream = (__bridge NSInputStream *)readStream; 
      [inputStream setDelegate:self]; 
      [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
      [inputStream open]; 

      //Setup outputstream 
      outputStream = (__bridge NSOutputStream *)writeStream; 
      [outputStream setDelegate:self]; 
      [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
      [outputStream open]; 
     } 
} 

- (int)streamClose; 
{ 
     CFReadStreamSetProperty((__bridge CFReadStreamRef)(inputStream), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 
     CFReadStreamSetProperty((__bridge CFReadStreamRef)(outputStream), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 

     //Close and reset inputstream 
     [inputStream setDelegate:nil]; 
     [inputStream close]; 
     [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
     inputStream = nil; 

     //Close and reset outputstream 
     [outputStream setDelegate:nil]; 
     [outputStream close]; 
     [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
     outputStream = nil; 
} 

Ten kod działa poprawnie, gdy otwieram i zamykam strumień wiele razy. Kiedy sprawdzam swoją aplikację pod kątem wycieków pamięci za pomocą Instrumentów, powiedział, że funkcja CFStreamCreatePairWithSocketToHost wycieka z pamięci o 72%. Czy ktoś wie, co robię źle? Nie mogę tego rozgryźć.

Odpowiedz

11

Dodaj CFRelease((CFStreamRef)inputStream); i CFRelease((CFStreamRef)outputStream); w metodzie streamClose.

Kiedy CFStreamCreatePairWithSocketToHost powraca własność readStream i writeStream przechodzi na Ciebie:

obiekty
Ownership follows the Create Rule in Memory Management Programming Guide for Core Foundation. 

Foundation Rdzeń musi być wyraźnie zwolniony nawet przy użyciu łuku:

The compiler does not automatically manage the lifetimes of Core Foundation objects; you 
must call CFRetain and CFRelease (or the corresponding type-specific variants) as dictated 
by the Core Foundation memory management rules (see Memory Management Programming Guide 
for Core Foundation). 

Ewentualnie zmienić tę linię (i odpowiadająca linia dla outputStream):

inputStream = (__bridge NSInputStream *)readStream; 

do:

inputStream = (__bridge_transfer NSInputStream *)readStream; 

To dlatego readStream posiada znakomite zachować rachubę który ARC nie jest świadomy. Poprzez nadanie ARC prawa własności do tego wskaźnika, dajesz mu pozwolenie na zwolnienie wskaźnika w odpowiednim czasie. Więcej informacji: 1, 2

+0

Używam automatycznego liczenia odwołań w moim projekcie, więc nie mogę używać wersji. Czy robi to automatycznie dla mnie? –

+0

sprawdź moją aktualizację – Mar0ux

+0

To zadziałało! Nie ma już wycieków pamięci. Myślę, że masz na myśli NSInputStream zamiast NSString w twojej odpowiedzi? –

Powiązane problemy