diff --git a/SocketRocket/SRWebSocket.m b/SocketRocket/SRWebSocket.m index 83f3e128f..cbbfc50a9 100644 --- a/SocketRocket/SRWebSocket.m +++ b/SocketRocket/SRWebSocket.m @@ -1072,17 +1072,9 @@ - (void)_pumpWriting; _inputStream.streamStatus != NSStreamStatusClosed) && !_sentClose) { _sentClose = YES; - - @synchronized(self) { - [_outputStream close]; - [_inputStream close]; - - - for (NSArray *runLoop in [_scheduledRunloops copy]) { - [self unscheduleFromRunLoop:[runLoop objectAtIndex:0] forMode:[runLoop objectAtIndex:1]]; - } - } - + + [self _scheduleCleanup]; + if (!_failed) { [self.delegateController performDelegateBlock:^(id _Nullable delegate, SRDelegateAvailableMethods availableMethods) { if (availableMethods.didCloseWithCode) { @@ -1090,8 +1082,6 @@ - (void)_pumpWriting; } }]; } - - [self _scheduleCleanup]; } } @@ -1126,33 +1116,42 @@ - (void)_scheduleCleanup } _cleanupScheduled = YES; + } + + // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves: + // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc + NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO]; + [[NSRunLoop SR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; +} - // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves: - // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc - NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO]; - [[NSRunLoop SR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; +- (void)removeAllFromRunLoops { + for (NSArray *runLoop in [_scheduledRunloops copy]) { + [self unscheduleFromRunLoop:[runLoop objectAtIndex:0] forMode:[runLoop objectAtIndex:1]]; } } - (void)_cleanupSelfReference:(NSTimer *)timer { - @synchronized(self) { - // Nuke NSStream delegate's - _inputStream.delegate = nil; - _outputStream.delegate = nil; - - // Remove the streams, right now, from the networkRunLoop - [_inputStream close]; - [_outputStream close]; - } + [_inputStream close]; + [_outputStream close]; + + [self removeAllFromRunLoops]; + + _inputStream.delegate = nil; + _outputStream.delegate = nil; + + //this is done to make sure that last request in the loop, is for setting _selfRetain to nil + NSTimer *selfRefTimer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(releaseSelfRef) userInfo:nil repeats:NO]; + [[NSRunLoop SR_networkRunLoop] addTimer:selfRefTimer forMode:NSDefaultRunLoopMode]; +} - // Cleanup selfRetain in the same GCD queue as usual +- (void)releaseSelfRef { + dispatch_async(_workQueue, ^{ _selfRetain = nil; }); } - static const char CRLFCRLFBytes[] = {'\r', '\n', '\r', '\n'}; - (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler;