I use NSInputstream
& NSOutputstream
to setup a connection and send data. My stream object has a function to open and close the stream. I use the following code:
@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;
}
This code works fine when I open and close the stream many times. When I check my app for memory leaks with Instruments, it said that the function CFStreamCreatePairWithSocketToHost
is leaking memory by 72%. Does someone know what I am doing wrong? I can't figure it out.
Xcode's Memory Graph Debugger If you haven't used this yet, it's easy to access while developing. Tapping on the icon will pause your application and generate a graph of the objects with their references to other objects. If there's leaked memory detected, you will see purple icons on the left pane of Xcode.
As per Apple, a memory leak is:Memory that was allocated at some point, but was never released and is no longer referenced by your app. Since there are no references to it, there's now no way to release it and the memory can't be used again.
Diagnose the Memory Leak Now, it's time to open the leaks instrument: Choose “Xcode” in the top left of the screen. Expand “Open Developer Tool,” and select “Instruments” Now choose “Leaks,” and make sure you have chosen your target app and device at the top (“Choose a profiling template for…”):
Only capture variables as unowned when you can be sure they will be in memory whenever the closure is run, not just because you don't want to work with an optional self . This will help you prevent memory leaks in Swift closures, leading to better app performance.
Add CFRelease((CFStreamRef)inputStream);
and CFRelease((CFStreamRef)outputStream);
in the streamClose
method.
When CFStreamCreatePairWithSocketToHost
returns, ownership of readStream
and writeStream
is passed onto you:
Ownership follows the Create Rule in Memory Management Programming Guide for Core Foundation.
Core Foundation objects need to be explicitly released even when using 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).
Alternatively, change this line (and corresponding line for outputStream
):
inputStream = (__bridge NSInputStream *)readStream;
to:
inputStream = (__bridge_transfer NSInputStream *)readStream;
This is because readStream has an outstanding retain count which ARC is not aware of. By giving ARC the ownership of this pointer, you are giving it permission to release the pointer at appropriate time. Further reading: 1, 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With