我在sendSynchronousRequest
上使用NSURLConnection
方法从服务器加载图像。它在网络连接速度很快时工作正常,但在连接速度很慢时崩溃我的应用程序。我做错了什么?
[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"image\";filename=\"%@.jpg\"\r\n",uploadImageName] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[NSData dataWithData:UIImageJPEGRepresentation(Obj1.thumbImage, 0.5)]];
[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postRequest setHTTPBody:postBody];
NSData *returndata=[NSURLConnection sendSynchronousRequest:postRequest returningResponse:nil error:nil];
NSString *string=[[NSString alloc]initWithData:returndata encoding:NSUTF8StringEncoding];
NSError *error;
NSString *path;
NSData *imageData;
if (error != nil && [string isEqualToString:@"success"]) {
//doing other work
}
我使用后台线程来运行所有这些代码。当我在网络连接缓慢时上传更多图像时,应用程序崩溃。
答案 0 :(得分:2)
可悲的是,我没有在代码片段中看到任何可能导致崩溃的明显内容。在这个答案的最后,我提供了我所做的代码示例,所以也许你可以将它与你的交叉引用。
有几点想法:
你说这适用于快速连接,但不能缓慢连接。这是从主线程运行同步查询的症状。如果您不小心从主队列执行了此同步调用,则在缓慢连接时,监视程序进程可能会终止您的应用程序。只要主线程没有响应,它就会这样做。
所以使用异步调用(正如你在其他问题中所追求的那样)或确保在后台队列中发生这种情况。
顺便说一句,你说你使用performSelectorInBackground
将其提交给后台线程。现在大多数人都会使用GCD或NSOperationQueue
。请参阅Concurrency Programming Guide。
一般情况下,如果有异常,我会要求您检查一些变量:
您没有向我们展示alloc
的{{1}} / init
。如果是postData
或nil
而不是NSData
,则可能会出现例外情况。
您应该确保NSMutableData
不是Obj1.thumbImage
。这也可能导致异常。
坦率地说,如果这是在快速连接而不是慢速连接,那么问题就不太可能在这些变量的基本设置中,而是你是否在其他地方异步更新它们(而不是同步你的更新) 线程编程指南的Synchronization部分或并发编程指南中的Eliminating Lock-Based Code的队列。在编写线程安全代码时,需要注意同步更改,在某些情况下,连接速度会影响行为。
如果这两点无法解决您的问题,那么我们真的需要深入了解您的异常。毋庸置疑,每当您发布有关异常的任何问题时,您必须:
告诉我们什么是例外
识别导致异常的行;你可以通过
来做到这一点查看堆栈跟踪以缩小问题的根源;
试试adding an exception breakpoint;有时,这将识别导致异常的精确线。
如果这不起作用,请尝试单步调试调试器中的代码。
诊断问题的最不优雅的方法是添加一堆nil
语句,这样你就可以弄清楚崩溃前代码的程度,以及各种变量是你期望的值。 / p>
如果你原谅观察,我感谢你试图让我们免于太多的代码(有时人们会发布大量不相关的代码;所以感谢你们放弃了我们),你们通常不会分享不够的代码。十分之九,人们所遭受的错误/异常是一些简单变量的结果尚未设置为您认为它具有的(例如未初始化等)。因此,您需要包含稍微更完整的代码示例,或者您的代码段应包含证明值有效的NSLog
,NSLog
或if
语句。
例如,您可能想要输入
assert
这可以确保自己在后台线程上运行。您可能还希望在访问时记录if ([NSThread isMainThread])
{
NSLog(@"%s: should not be on main thread!!!", __FUNCTION__);
}
和Obj1.thumbImage
。
我已经看到了你的一些问题,你(a)发布一些简单的代码,(b)告诉我们它在这个片段中的某个地方崩溃(但不是精确到哪里)和(c)向我们保证价值通过非常简单的代码片段都是有效的(即使代码片段没有说明)。简单的现实,通常不是所有这三个条件都可以同时成立。当人们发布崩溃时,问题就像在代码本身中传递给违规代码的变量一样。
一些不相关的观点:
另外,在postBody
中,您为sendSynchronousRequest
指定了nil
。如果API为您提供诊断错误成功或失败的机会,您应该利用它。
使用error
确实是最糟糕的情况,会导致严重的数据丢失。如果人性化,请返回UIImageJPEGRepresentation
的来源(如何创建?UIImage
?)。如果你不能这样做,可以考虑NSData
,因为它仍然享受压缩,但数据丢失更少。有时你必须做UIImagePNGRepresentation
,但认为它是最后的工具。
如果您的服务器只返回“成功”文本字符串,那么我想这就是您所能做的。如果可能,最好是您可以对服务器进行编程以返回JSON响应,您可以轻松地为不同类型的错误/响应使用/解析不同的返回代码。
无论如何,这是一个有效的上传例程:
UIImageJPEGRepresentation
答案 1 :(得分:0)
追踪这个...
添加异常断点。这样就会在发生异常的行上停止调试器。
后台线程没有自己的异常处理程序,因此它们会生成一个信号并导致进程崩溃。所以你可以添加自己的东西,特别是这样的,系统调用正在生成异常,你没有一个好的方法来阻止它。
@try{
NSData *returndata=[NSURLConnection sendSynchronousRequest:postRequest returningResponse:nil error:nil];
NSString *string=[[NSString alloc]initWithData:returndata encoding:NSUTF8StringEncoding];
}
@catch(NSException *e)
{
NSLog(@"caught exception: %@",e);
//you could also iterate over: - (NSArray *)callStackSymbols NS_AVAILABLE(10_6, 4_0);
}