POSIX error 12 (“Cannot allocate memory”) while uploading files from an iPhone

前端 未结 3 1401
长情又很酷
长情又很酷 2021-02-08 15:59

I\'m working on an iPhone application that involves uploading full photos from the camera (generally between 1.5 to 2.0 MB each) as well as their thumbnails (much smaller) to Am

相关标签:
3条回答
  • 2021-02-08 16:02

    Have resolved this error with using operation for request (NSMutableUrlConnection) with @autorelease{} for main function. NSPOXIS appears only sometimes.

    - (void)main
     NSURLConnection* connection;
        @autoreleasepool //urgently needed for 3G upload
        {
    
            self.currentRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"test.php"]];
            [self.currentRequest setHTTPMethod:@"PUT"];
    
            [self.currentRequest setHTTPBody:self.data];//inpustStream doesn't work
    
            connection = [NSURLConnection connectionWithRequest:self.currentRequest delegate:self];
            [connection start];
    
        }//end autorelease pool
    
            do 
            {
    
                [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
                if ([self isCancelled])
                {
                    connection          = nil;
                    isFailed = YES;
                    break;
                }
                self.status(statusUpdateMessage);
            } 
            while (!isFailed && !isCompleted);
            [timer invalidate];//test
            timer = nil;
    
    //corresponding of status via blocks
            self.completed(!isFailed);
            self.status(isFailed ? errorMessage : @"Completed");
            if (isFailed)
            {
                self.failed(errorMessage != nil ? errorMessage : @"Undefined error");
            }
    
            self.data = nil;
            self.currentRequest = nil;
    
            connection = nil;
    
    }
    
    0 讨论(0)
  • 2021-02-08 16:12

    The only way I was able to work around this issue, is using sockets directly and forming HTTP header manually. So my uploading code currently looks like this:

    - (void)socketClose
    {
        [_inputStream setDelegate:nil];
        [_inputStream close];
        [_inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        SCR_RELEASE_SAFELY(_inputStream);
    
        [_outputStream setDelegate:nil];
        [_outputStream close];
        [_outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        SCR_RELEASE_SAFELY(_outputStream);
    
        SCR_RELEASE_SAFELY(_headerBuffer);
    }
    
    - (void)sendRequest
    {
        [self socketClose];
        SCR_RELEASE_SAFELY(_headerBuffer);
    
        if (!_shouldCancel)
        {
            NSString *httpMessage = [NSString stringWithFormat:@"POST upload.php HTTP/1.1\r\n"
                                     "Host:"
    #ifndef TESTBED
                                     " %@"
    #endif
                                     "\r\n"
                                     "User-Agent: MyApp/3.0.0 CFNetwork/534 Darwin/10.7.0\r\n"
                                     "Content-Length: %d\r\n"
                                     "Accept: */*\r\n"
                                     "Accept-Language: en-us\r\n"
                                     "Accept-Encoding: gzip, deflate\r\n"
                                     "Content-Type: application/x-www-form-urlencoded\r\n"
                                     "Connection: keep-alive\r\n\r\n"
                                     "data="
    #ifndef TESTBED
                                     , [self.serverUrl host]
    #endif
                                     , _bytesToUpload];
    
            NSString *key = @"data=";
            NSData *keyData = [key dataUsingEncoding:NSASCIIStringEncoding];
            _bytesToUpload -= [keyData length];
            _bytesToUpload = MAX(0, _bytesToUpload);
    
            _headerBuffer = [[NSMutableData alloc] initWithData:[httpMessage dataUsingEncoding:NSUTF8StringEncoding]];
    
            _writtenDataBytes = 0;
    
            CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault
                                               , (CFStringRef)[self.serverUrl host]
    #ifdef TESTBED
                                               , 8888
    #else
                                               , 80
    #endif
                                               , (CFReadStreamRef *)(&_inputStream)
                                               , (CFWriteStreamRef *)(&_outputStream));
    
            [_inputStream setDelegate:self];
            [_outputStream setDelegate:self];
    
            [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
            [_inputStream open];
            [_outputStream open];
        }
    }
    
    - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
    {
        if (_outputStream == theStream)
        {
            switch (streamEvent)
            {
                case NSStreamEventOpenCompleted:
                {
                    [self regenerateTimeoutTimer];
                    break;
                }
                case NSStreamEventHasSpaceAvailable:
                {
                    SCR_RELEASE_TIMER(_timeoutTimer);
                    NSInteger length = _headerBuffer.length;
    
                    if (length > 0)
                    {
                        NSInteger written = [_outputStream write:(const uint8_t *)[_headerBuffer bytes] maxLength:length];
                        NSInteger rest = length - written;
    
                        if (rest > 0)
                        {
                            memmove([_headerBuffer mutableBytes], (const uint8_t *)[_headerBuffer mutableBytes] + written, rest);
                        }
    
                        [_headerBuffer setLength:rest];
                    }
                    else
                    {
                        const uint8_t *dataBytes = [_data bytes];
    
                        while ([_outputStream hasSpaceAvailable] && (_writtenDataBytes < _bytesToUpload))
                        {
                            NSInteger written = [_outputStream write:dataBytes
                                                           maxLength:MIN(_dataLength, _bytesToUpload - _writtenDataBytes)];
    
                            if (written > 0)
                            {
                                _writtenDataBytes += written;
                            }
                        }
                    }
    
                    [self regenerateTimeoutTimer];
    
                    break;
                }
                case NSStreamEventErrorOccurred:
                {
                    SCR_RELEASE_TIMER(_timeoutTimer);
                    [self reportError:[theStream streamError]];                
                    break;
                }
                case NSStreamEventEndEncountered:
                {
                    SCR_RELEASE_TIMER(_timeoutTimer);
                    [self socketClose];
                    break;
                }
            }
        }
        else if (_inputStream == theStream)
        {
            switch (streamEvent)
            {
                case NSStreamEventHasBytesAvailable:
                {
                    SCR_RELEASE_TIMER(_timeoutTimer);
    
                    /* Read server response here if you wish */
    
                    [self socketClose];
    
                    break;
                }
                case NSStreamEventErrorOccurred:
                {
                    SCR_RELEASE_TIMER(_timeoutTimer);
                    [self reportError:[theStream streamError]];
                    break;
                }
                case NSStreamEventEndEncountered:
                {
                    SCR_RELEASE_TIMER(_timeoutTimer);
                    [self socketClose];
                    break;
                }
            }
        }
    }
    

    Although ASIHTTPRequest could work here, we decided to walk away from such dependencies both in order to get performance and to keep everything under our own control accurately. You can use Wireshark tool in order to debug this kind of things.

    0 讨论(0)
  • 2021-02-08 16:17

    The key to getting around this issue is to upload the file using a stream. When using NSMutableURLRequest, this can be accomplished using something similar to the following:

    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPBodyStream:[NSInputStream inputStreamWithFileAtPath:filePath]];
    

    When using ASIHTTPRequest, streaming a file is accomplished with this:

    ASIHTTPRequest* request = [ASIHTTPRequest requestWithURL:url];
    [request setPostBodyFilePath:filePath];
    rRequest.shouldStreamPostDataFromDisk = YES;
    
    0 讨论(0)
提交回复
热议问题