2013-05-01 2 views
6

Я использую NSInputstream & NSOutputstream, чтобы установить соединение и отправить данные. Мой объект потока имеет функцию открытия и закрытия потока. Я использую следующий код:Утечки памяти в 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; 
} 

Этот код отлично работает, когда я открываю и закрываю поток много раз. Когда я проверяю свое приложение на утечку памяти с помощью инструментов, он сказал, что функция CFStreamCreatePairWithSocketToHost пропускает память на 72%. Кто-нибудь знает, что я делаю неправильно? Я не могу понять.

ответ

11

Добавить CFRelease((CFStreamRef)inputStream); и CFRelease((CFStreamRef)outputStream); в метод streamClose.

Когда CFStreamCreatePairWithSocketToHost возвращается, владение readStream и writeStream передаются на вас:

объектов
Ownership follows the Create Rule in Memory Management Programming Guide for Core Foundation. 

Основного фонда должны быть явно выпущены даже при использовании 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). 

В качестве альтернативы, изменить эту строку (и соответствующей линии для outputStream):

inputStream = (__bridge NSInputStream *)readStream; 

к:

inputStream = (__bridge_transfer NSInputStream *)readStream; 

Это потому, что ReadStream имеет выдающийся сохранить количество которых ARC не знает. Предоставляя ARC право собственности на этот указатель, вы даете ему разрешение на выпуск указателя в соответствующее время. Дальнейшее чтение: 1, 2

+0

Я использую автоматический подсчет ссылок в моем проекте, поэтому я не могу использовать выпуск. Это делается автоматически для меня? –

+0

проверить мои обновления – Mar0ux

+0

Это сработало! Больше нет утечек памяти. Я думаю, вы имеете в виду NSInputStream вместо NSString в своем ответе? –

Смежные вопросы