简体   繁体   中英

What is the reason that AFMultipartBodyStream does not support scheduleInRunLoop mechanism?

Though AFMultipartBodyStream of AFNetworking lib is a subclass of NSStream conforming to NSStreamDelegate protocol, it could not be processed as with standard way of a regular NSStream . Namely, AFMultipartBodyStream could not be handled with stream event. I looked into the code of AFMultipartBodyStream , and found that it intentionally disabled the scheduleInRunLoop method of NSInputStream abstract class:

- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop
              forMode:(__unused NSString *)mode
{}

- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop
              forMode:(__unused NSString *)mode
{}

Any specific reason? Is it a way to make it support the standard stream event mechanism so that the stream data handling can be done asynchronously with stream:handleEvent: event handler?

After studying the implementation of AFMultipartBodyStream, I noticed that the way of current implementation could not support the asynchronous way of regular stream IO handling. I then enhanced AFMultipartBodyStream to provide a stream which was connected with the internal multipart data structure, and thus the holder of this AFMultipartBodyStream can handle the multipartbody data as the regular stream which can be scheduled in the runloop. below code snippet shows the main idea:

-(NSInputStream *)inputStream {
    // If _inputStream has not been connected with HTTPBodyParts data, establish the connection
    if (!_inputStream) {
        NSParameterAssert([self.HTTPBodyParts count] != 0);
        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
        CFIndex bufferSize = self.contentLength;
        CFStreamCreateBoundPair(NULL, &readStream, &writeStream, bufferSize);
        _inputStream = (__bridge_transfer NSInputStream *)readStream;
        _outputStream = (__bridge_transfer NSOutputStream *)writeStream;
        [_outputStream setDelegate:self];

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSLog(@"\n====in async block of inputStream....====\n");

            [self->_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [self open];
            [self->_outputStream open];
            NSInteger totalBytesSent = self.contentLength;
            while (totalBytesSent > 0 && [self->_outputStream hasSpaceAvailable]) {
                uint8_t buffer[1024];
                NSInteger bytesRead = [self read:buffer maxLength:1024];
                totalBytesSent -= bytesRead;
                NSLog(@"\n====buffer read (%ld): [%s]====\n", (long)bytesRead, buffer);
                if (self.streamError || bytesRead < 0) {
                    break;
                }

                NSInteger bytesWritten = [self->_outputStream write:buffer maxLength:(NSUInteger)bytesRead];
                if (self->_outputStream.streamError || bytesWritten < 0) {
                    NSLog(@"\n====Socket write failed[%@]====\n", self->_outputStream.streamError);
                    break;
                }

                if (bytesRead == 0 && bytesWritten == 0) {
                    break;
                }
            }

            [self->_outputStream close];
            [self->_outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        });
    }

    return _inputStream;
}




// Added
- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop
                  forMode:(__unused NSString *)mode
{
    // Setup the input stream for body stream data consuming
    NSInputStream *inputStream = [self inputStream];
    NSParameterAssert(inputStream == self.inputStream);
    [inputStream setDelegate:self.delegate_];
    [inputStream scheduleInRunLoop:aRunLoop forMode:mode];
    [inputStream open];
}
// Added
- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop
                  forMode:(__unused NSString *)mode
{
    if (_inputStream) {
        [_inputStream setDelegate:[self delegate]];
        [_inputStream removeFromRunLoop:aRunLoop forMode:mode];
        [_inputStream close];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM