最近做的iPhone项目中有一如下功能:

app在用户许可后将本地Photos的照片上传到服务器,期间用户可以做其他任何操作,等上传成功后弹出一个toast通知用户。

原先的代码结构是:

  1. 获取照片的操作放在NSOperation的子类A中
  2. 获取完照片后,逐个生成一个上传类B(此上传类是ASIFormDataRequest的子类),并把它添加到NSOperationQueue中。

其中operationqueue设置了最大运行数是1,但是实际测试下来发现所有的上传都是并发的,一查代码,发现上传类B居然没有实现main,就一个init函数。初始化完之后直接startAsynchronous了,然后返回self。真是奇葩~~

于是将上传类B修改,添加了main函数,但是运行的时候出错:

- (void)reportFinished
{
if (delegate && [delegate respondsToSelector:didFinishSelector]) {
[delegate performSelector:didFinishSelector withObject:self];
}---------------------->提示bad_access的错误 #if NS_BLOCKS_AVAILABLE
if(completionBlock){
completionBlock();
}
#endif if (queue && [queue respondsToSelector:@selector(requestFinished:)]) {
[queue performSelector:@selector(requestFinished:) withObject:self];
}
}

查看delegate的值,发现已经overrelease了。B在设置的时候,将delegate设置为A的实例了,A的实例怎么会不等B的返回就结束了呢?

原来A本身是一个operation,假设运行在次线程 M中。B因为是继承ASIFormDataRequest,其实也是一个NSOperation,也就是说B运行的时候也是运行在次线程N中的。因为B使用的是异步运行,N必然不同于M。而A在将上传操作结束完以后,就结束了,系统就会回收A的内存。这个时候在N中运行的B尚未收到响应。等到response返回的时候,A早就已经释放了,所以就会有如上的错误。

怎么解决呢?有同事是把A设置为property。这样可以解决,但是当需要调用A的类很多的时候,就会比较麻烦。

其实解决的办法很简单,就是在A中重载isFinished方法,当确定所有的照片上传上去后返回YES否则返回NO,这样我们就可以控制A,避免系统“过早”的释放。

与此同时我们发现,ASIHttpRequest的delegate响应都会路由到主线程:

- (void)requestFinished
{
#if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
NSLog(@"[STATUS] Request finished: %@",self);
#endif
if ([self error] || [self mainRequest]) {
return;
}
if ([self isPACFileRequest]) {
[self reportFinished];
} else {
[self performSelectorOnMainThread:@selector(reportFinished) withObject:nil waitUntilDone:[NSThread isMainThread]];
}
}

stackoverflow上有关于这样做的讨论,这里要说明的是因为B是运行在后台,delegate是A,不需要在主线程响应。我们可以在B中重载上述函数,将performSelectorOnMainThread:函数去掉,直接调用reportFinished。

进一步考虑,iOS上获取本地照片现在一般用ALAssetsLibrary,这个库一般是用block去枚举,换言之获得照片内容的操作已经是在次线程中操作的了。

这样一来A也就可以不需要是NSOperation,是个一般的NSObject即可。

最近项目添加了很多“奇葩”的功能,可是参与的决定权不在自己这边,虽然我列出了很多不应该这样做的理由和依据。但是需求人员都以本国的用户需求为借口——看来公司越来越成为外资公司在华的外包公司了。这个职位也变得越来越乏味,虽然不见得能马上跳槽,但是也学会了在“逆境”中坚强:学习产品的设计,和非开发人员的沟通,重构代码。觉得有句话说的真好:要想做自己想做的事,就得先做自己不想做的事。

与诸君共勉!

多线程-NSOperation中使用ASIHttpRequest注意事项的更多相关文章

  1. C++ 关于MFC多线程编程中的一些注意事项 及自定义消息的处理

    在多线程编程中,最简单的方法,无非就是利用 AfxBeginThread  来创建一个工作线程,看一下这个函数的说明: CWinThread* AFXAPI AfxBeginThread( AFX_T ...

  2. iPhone SDK中多线程的使用方法以及注意事项

    多线程iphonethreadapplication编程嵌入式 然现在大部分PC应用程序都支持多线程/多任务的开发方式,但是在iPhone上,Apple并不推荐使用多线程的编程方式.但是多线程编程毕竟 ...

  3. iOS多线程 NSOperation的用法

    上一篇写了 GCD 的使用,接下来就了解一下 NSOperation ,NSOperation是苹果对 GCD 的 OC 版的一个封装,但是相对于GCD来说可控性更强,并且可以加入操作依赖. NSOp ...

  4. Linux 多线程应用中如何编写安全的信号处理函数

    http://blog.163.com/he_junwei/blog/static/1979376462014021105242552/ http://www.ibm.com/developerwor ...

  5. iOS之多线程NSOperation

    目前在 iOS 和 OS X 中有两套先进的同步 API 可供我们使用:NSOperation 和 GCD .其中 GCD 是基于 C 的底层的 API ,而 NSOperation 则是 GCD 实 ...

  6. iOS 多线程 NSOperation、NSOperationQueue

    1. NSOperation.NSOperationQueue 简介 NSOperation.NSOperationQueue 是苹果提供给我们的一套多线程解决方案.实际上 NSOperation.N ...

  7. iOS 开发多线程 —— NSOperation

    本文是根据文顶顶老师的博客学习而来,转载地址:http://www.cnblogs.com/wendingding/p/3809042.html 一.NSOperation简介 1.简单说明 NSOp ...

  8. iOS多线程---NSOperation介绍和使用

    1.  NSOperation实现多线程编程,需要和NSOperationQueue一起使用. (1)先将要执行的操作封装到NSOperation中 (2)将NSOperation对象添加到NSOpe ...

  9. 四:多线程--NSOperation简单介绍

    一.NSOperation简介 1.NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQu ...

随机推荐

  1. 使用 Swagger UI 与 Swashbuckle 创建 RESTful Web API 帮助文件

    作者:Sreekanth Mothukuru 2016年2月18日 本文旨在介绍如何使用常用的 Swagger 和 Swashbuckle 框架创建描述 Restful API 的交互界面,并为 AP ...

  2. JQuery的ajax方法

    1.使用方式: 由于是全局方法,所以调用简单:$.ajax(); 2.可输入参数: 最好是写成一个json形式,个人不建议用链式,那样看上去不太好. 参数名称 类型 描述 dataType strin ...

  3. photosop快速对白色背景图片进行抠图

    因为其中有个作业,做个图书馆的小网页.所以打算取图书馆logo上面那几个字. 图片如下: 因为是白色背景,一开始打算使用魔棒工具,不过效果不好. 后来百度了下,使用色彩范围可以快速抠图 打开photo ...

  4. GCD常用方法

    1.延迟操作 2.一次性代码 3.队列组 /** * 延迟执行 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC ...

  5. ExtJs布局之BOX

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  6. C# 实现抓取网站页面内容

    抓取新浪网的新闻栏目,如图所示: 使用 谷歌浏览器的查看源代码: 通过分析得知,我们所要找的内容在以下两个标签之间: <!-- publish_helper name='要闻-新闻' p_id= ...

  7. C Primer Plus之结构和其他数据形式

    声明和初始化结构指针 声明结构化指针,例如: struct guy * him; 初始化结构指针(如果barney是一个guy类型的结构),例如: him = &barney; 注意:和数组不 ...

  8. 用C#实现Base64处理,加密解密,编码解码

    using System; using System.Text; namespace Common { /// <summary> /// 实现Base64加密解密 /// 作者:周公 / ...

  9. MongoDB (十一) MongoDB 排序文档

    sort() 方法 要在 MongoDB 中的文档进行排序,需要使用sort()方法. sort() 方法接受一个文档,其中包含的字段列表连同他们的排序顺序.要指定排序顺序1和-1. 1用于升序排列, ...

  10. 【转】Linux写时拷贝技术(copy-on-write)

    http://www.cnblogs.com/biyeymyhjob/archive/2012/07/20/2601655.html 源于网上资料 COW技术初窥: 在Linux程序中,fork()会 ...