referenceretainnsstreamnsrunloop

Does [NSStream scheduleInRunLoop: forMode:] retain the NSStream?


I want to send and receive some data using nsstreams. I don't want to clutter my code so much, so I was wondering:

Do I need to keep a strong reference to a NSStream or is [NSStream scheduleInRunLoop: forMode:] creating a strong reference to it?

I couldn't find any documentation on that. I have tried, and it works without having an own strong reference.

I was hoping someone can confirm or refute that finding.


Solution

  • Yes, after scheduling NSStream in RunLoop its reference count grows. I think that this code is enough to prove it:

    NSInputStream* nStream = [[NSInputStream alloc] initWithFileAtPath:path];
    NSLog(@"Stream retain count A is %ld", CFGetRetainCount((__bridge CFTypeRef)nStream));
    NSValue* val = [NSNumber valueWithPointer:(__bridge const void * _Nullable)(nStream)];// not increment reference counter
    NSLog(@"Stream retain count B is %ld", CFGetRetainCount(val.pointerValue));
    [nStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    NSLog(@"Stream retain count C is %ld", CFGetRetainCount(val.pointerValue));
    nStream = nil;
    NSLog(@"Stream retain count D is %ld", CFGetRetainCount(val.pointerValue));
    

    And console output:

     Stream retain count A is 1
     Stream retain count B is 1
     Stream retain count C is 3
     Stream retain count D is 2
    

    So adding to NSRunLoop increases number references by 2. After nullification of original strong reference counter value remains positive, and this prevents deallocation of stream object.

    Because object still exist, will respond to this code:

    [(__bridge const NSInputStream*)val.pointerValue open];
    [(__bridge const NSInputStream*)val.pointerValue close];
    

    But next line will cause crash - now stream is removed from NSRunLoop. All references to it was removed - what remains is value of pointer to - now deallocated - object (behaves similarly to assigned pointer). Call to deallocated object always means EXC_BAD_ACCESS...

    NSLog(@"Stream retain count E is %ld",
    CFGetRetainCount(val.pointerValue));//crash here