예, RunLoop에서 NSStream을 예약 한 후에 참조 횟수가 늘어납니다. 이 코드가 그것을 증명하기에 충분하다고 생각 :
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));
그리고 콘솔 출력 :
Stream retain count A is 1
Stream retain count B is 1
Stream retain count C is 3
Stream retain count D is 2
그래서 NSRunLoop에 추가 원래 강한 참조 카운터 값의 무효는 여전히 긍정적 후 2로 번호 참조를 증가 이는 스트림 객체의 할당 해제를 방지합니다. 객체가 여전히 존재하기 때문에
,이 코드에 응답합니다 :
[(__bridge const NSInputStream*)val.pointerValue open];
[(__bridge const NSInputStream*)val.pointerValue close];
그러나 다음 줄이 충돌의 원인이됩니다 - 지금 스트림이 NSRunLoop에서 제거됩니다. 이 객체에 대한 모든 참조가 제거되었습니다. 남아있는 것은 포인터의 값입니다. 현재 할당 해제 된 객체입니다 (포인터는 assigned
포인터와 유사하게 동작 함). 할당이 해제 된 객체는 항상 EXC_BAD_ACCESS
의미에 ... 전화
NSLog(@"Stream retain count E is %ld",
CFGetRetainCount(val.pointerValue));//crash here
또한 NSRunLoop에 추가 한 후 NSTimer의 동작과 비유를 찾을 수 있습니다. NSTimer는 NSRunLoop에서 제거하기위한'invalidate' 메소드를 가지고 있습니다. NSStream 해당 사항은'close'입니다. –