2013-05-01 12 views
6

Io uso NSInputstream & NSOutputstream per impostare una connessione e inviare dati. Il mio oggetto stream ha una funzione per aprire e chiudere lo stream. Io uso il seguente codice:Perdite di memoria in 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; 
} 

Questo codice funziona bene quando apro e chiudo il flusso molte volte. Quando controllo la mia app per perdite di memoria con gli strumenti, è stato detto che la funzione CFStreamCreatePairWithSocketToHost sta perdendo memoria del 72%. Qualcuno sa cosa sto sbagliando? Non riesco a capirlo.

risposta

11

Aggiungi CFRelease((CFStreamRef)inputStream); e CFRelease((CFStreamRef)outputStream); nel metodo streamClose.

Quando CFStreamCreatePairWithSocketToHost rendimenti, la proprietà del readStream e writeStream viene passato su di te:

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

Nucleo Fondazione devono essere esplicitamente rilasciato anche quando si utilizza ARC:

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). 

In alternativa, cambiare questa linea (e riga corrispondente per outputStream):

inputStream = (__bridge NSInputStream *)readStream; 

a:

inputStream = (__bridge_transfer NSInputStream *)readStream; 

Questo perché readStream ha un eccezionale mantenere conteggio che ARC non è a conoscenza di. Dando a ARC la proprietà di questo puntatore, gli si concede il permesso di rilasciare il puntatore al momento opportuno. Ulteriori letture: 1, 2

+0

Uso il conteggio dei riferimenti automatico nel mio progetto, quindi non posso usare la versione. È fatto automaticamente per me? –

+0

controlla il mio aggiornamento – Mar0ux

+0

Ha funzionato! Nessuna perdita di memoria. Penso che intendiate NSInputStream al posto di NSString nella vostra risposta? –