macos - NSMutableURLRequest 和内存问题

标签 macos cocoa nsurlconnection nsdata nsmutableurlrequest

早上好, 我正在开发一个上传一些文件的应用程序;没有真正的问题,但只有一个大问题:如果我尝试上传 1GB 的文件,它会分配 1GB 的内存,你可以理解这不是一件好事。

这是我的代码:我将数据分配为 NSData,然后使用 NSMutableURLRequest + NSURLConnection 上传它们;我的问题是:有什么方法可以做到这一点而不需要分配整个内存?我已经搜索过,但什么也没找到...

_uploadDataFile是之前分配的NSData子类实例。

NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://my.server/page"]
                                                            cachePolicy:NSURLRequestReloadIgnoringCacheData
                                                        timeoutInterval:60.0] autorelease];

NSData *dataFile;

if (_uploadDataFile == nil) {
    NSError *error = nil;
    dataFile = [[[NSData alloc] initWithContentsOfFile:@"pathToFile" options:NSDataReadingUncached error:&error] autorelease];

    if (error) {
        NSLog(@"Error %i: %@", [error code], [error localizedDescription]);
        [self fermaUpload]; //Stop Upload
        return;
    }
}

else 
    dataFile = [_uploadDataFile file];

NSMutableDictionary *dictPost = [[[NSMutableDictionary alloc] init] autorelease];
[dictPost setValue:dataFile forKey:@"uploads[]"];

NSData *mutData = [self dataForPOSTWithDictionary:dictPost boundary:@"0194784892923" nomeFile:[@"pathToFile" lastPathComponent]];

NSString *postLength = [NSString stringWithFormat:@"%d", [mutData length]];

[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"multipart/form-data; boundary=0194784892923" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:mutData];
[request setHTTPShouldHandleCookies:YES];

theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

这是 (NSData *)dataForPOSTWithDictionary:boundary:nomeFile: 方法的样子:

- (NSData *)dataForPOSTWithDictionary:(NSDictionary *)aDictionary boundary:(NSString *)aBoundary nomeFile:(NSString *)nomeFile {
NSArray *myDictKeys = [aDictionary allKeys];
NSMutableData *myData = [NSMutableData dataWithCapacity:1];
NSString *myBoundary = [NSString stringWithFormat:@"--%@\r\n", aBoundary];

for(int i = 0;i < [myDictKeys count];i++) {
    id myValue = [aDictionary valueForKey:[myDictKeys objectAtIndex:i]];
    [myData appendData:[myBoundary dataUsingEncoding:NSUTF8StringEncoding]];
    //if ([myValue class] == [NSString class]) {
    if ([myValue isKindOfClass:[NSString class]]) {
        [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", [myDictKeys objectAtIndex:i]] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[[NSString stringWithFormat:@"%@", myValue] dataUsingEncoding:NSUTF8StringEncoding]];
    } else if(([myValue isKindOfClass:[NSURL class]]) && ([myValue isFileURL])) {
        [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], [[myValue path] lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[NSData dataWithContentsOfFile:[myValue path]]];
    } else if(([myValue isKindOfClass:[NSData class]])) {
        [myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], nomeFile] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [myData appendData:myValue];
    } // eof if()

    [myData appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
} // eof for()
[myData appendData:[[NSString stringWithFormat:@"--%@--\r\n", aBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

return myData; } // eof dataForPOSTWithDictionary:boundary:

谢谢你,对我的英语感到抱歉。

最佳答案

一个最有趣的问题!有两种方法可以将正文数据输入 NSURLConnection/Request:

  • NSData
  • NSInputStream

不幸的是,这也不是你想要的开箱即用的东西,因为你想要上传一个文件+一些表单数据。理想情况下,您可以子类化 NSInputStream 以提供您需要的格式化数据。但是,我上次检查时,NSURLConnection 无法处理此类子类。相反,请执行以下操作:

  1. 使用 CFStreamCreateBoundPair() 创建一对流。这将返回一个 CFWriteStreamCFReadStream,它们分别免费桥接到 NSOutputStreamNSInputStream
  2. 将自己设置为输出流的委托(delegate)
  3. -setHTTPBodyStream: 在带有输入流的 URL 请求上
  4. 启动连接

现在应该定期调用输出流的委托(delegate)来请求数据。您需要输入 POST 数据,然后输入文件数据 block 。因此整个文件永远不会同时完全存在于内存中。

关于macos - NSMutableURLRequest 和内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7793311/

相关文章:

cocoa - iTunes 中具有额外排序功能的新的较高表格标题行是如何实现的?

ios - MPmovieplayer 播放问题获取 _itemFailedToPlayToEnd : in ios

node.js - 如何将使用 Sharp 库的无服务器框架应用程序部署到 AWS?

c++ - 什么是基于 >MACHINE< 的好 PPC 用于为顺序处理器分析代码

macos - 在 Mac 应用程序中显示表情符号图标

objective-c - 如何向字符串添加度数符号?

python - python "trial mode expires in x days"错误信息

objective-c - CFNotificationCenter 用法示例?

iPhone NSURLConnection : connectionDidFinishLoading - how to return a string to the calling method

ios - NSURLSession 委托(delegate) didCompleteWithError 未调用