http://d2100.com/questions/29022
作为依赖关系的另一个 NSOperation 添加时不调用 NSOperation dealloc
使用文书我看到很多我自定义的 NSOperation 永远不会被释放。我已经把一个断点放在 dealloc 方法中,它叫做永远不会。

我还注意到作为依赖关系的另一个 NSOperation 添加任何 NSOperation 时出现问题。如果我从我的代码中删除以下句子,称为 myOperation 的 dealloc 方法。

[otherOperation addDependency:myOperation];

我新建类 

@interface DownloadOperation:NSOperation

并声明了静态实例:

static DownloadOperation *downloadOperation;   //期望构造工厂方法,不必每次调用都alloc

+ (DownloadOperation*)sharedDownloadOperation

{

if(downloadOperation==nil)

{

downloadOperation=[[self alloc]init];

}

return downloadOperation;

}

- (void)initWithURL:(NSString*)url delegate:(id<downloadFinishDelegate>)delegate//delegate是资料下载结束的回调

{

_webReachable=[WebConnectionWebConnect];

_delegate=delegate;

_enc =CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);

_request=[[NSURLRequestrequestWithURL:[NSURLURLWithString:[url stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]retain];

self.XMLData=[NSMutableData data];

}

- (void)start            //NSOperation添加到queue自动执行的函数

{

if([NSURLConnectioncanHandleRequest:_request]&&_webReachable)

{

_connection=[[NSURLConnectionconnectionWithRequest:_requestdelegate:self]retain];

while (_connection!=nil) {

[[NSRunLoop  currentRunLoop]runMode:NSDefaultRunLoopMode    beforeDate:[NSDatedistantFuture]];

}

}

else

{

UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"无网络连接1" message:@"请检查网络" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];

[alert show];

[alert release];

}

}

调用类:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

self.tableView.UserInteractionEnabled=NO;

[[DownloadOperation sharedDownloadOperation]initWithURL:@"http://www.bart.gov/dev/eta/bart_eta.xml" delegate:self];

[queue  addOperation:[DownloadOperation sharedDownloadOperation]];

}

- (void)downloadFinish:(NSMutableData*)data //类:DownloadOperation下载完数据回调

{

self.tableView.userInteractionEnabled=YES;

}

结果执行一次正常,第二次出现错误:operation is executing and cannot be enqueued

后来也没解决,只好放弃静态变量,每次都重新创建DownloadOperation类的实例

在论坛上看到的类似案例,未验证,仅供参考

问:
I would like to restart a connection re-invoking [request 
startAsynchronous] (我出现类似问题,[operation start]  :operation is executing and cannot be enqueued) if for example the first request does not return 
expected results. 
The problem is that the second attempt to call startAsynchronous raise 
an exception:

*** Terminating app due to uncaught exception 
'NSInvalidArgumentException', reason: '*** -[NSOperationQueue 
addOperation:]: operation is finished and cannot be enqueued'

I'm pretty new to ASIHTTPRequest, so maybe I'm trying to do an 
unsupported operation... 
I'm doing something wrong? Should I create another request and then 
call startAsynchronous on it?

- (void)viewDidLoad { 
        [super viewDidLoad];

// remote asynchronous call 
        NSURL *url = [self getConnectionURL];

mainHTTPRequest = [[ASIHTTPRequest requestWithURL:url] retain]; 
        [mainHTTPRequest setDelegate:self]; 
        [mainHTTPRequest startAsynchronous];   //  ***** FIRST CALL  ***** 
}

- (void)requestFinished:(ASIHTTPRequest *)request { 
        NSString *responseString = [request responseString];

BOOL repeat = [self checkIfRepeatNeeded:responseString];

if (repeat) { 
                [request startAsynchronous];   //  ***** SECOND CALL  ***** 
                return; 
        }

// ... further processing... 
}

答:
> I would like to restart a connection re-invoking [request
> startAsynchronous] if for example the first request does not return
> expected results.
> The problem is that the second attempt to call startAsynchronous raise
> an exception:

> *** Terminating app due to uncaught exception
> 'NSInvalidArgumentException', reason: '*** -[NSOperationQueue
> addOperation:]: operation is finished and cannot be enqueued'

Yes, you cannot restart a request like this.

One option would be to make a copy of your request, and start that:

ASIHTTPRequest *newRequest = [[request copy] autorelease];
[newRequest startAsynchronous];

But, if you're just doing a simple GET request, you can just as easily create a new request with the same url.

问:

What if I have a model class with an ASIHTTPFormDataRequest *request ivar? Would something like this work?

- (void)dealloc {

[request clearDelegatesAndCancel];

[request release];

[super dealloc];

}

- (void)sendRequest {

[request clearDelegatesAndCancel];

[request release];

NSURL *url = [[NSURL alloc] initWithString:@"https://example.com/"];

request = [[ASIFormDataRequest alloc] initWithURL:url];

[url release];

request.delegate = self;

[request setPostValue:@"value1" forKey:@"key1"];

[request setPostValue:@"value2" forKey:@"key2"];

[request setPostValue:session forKey:@"iVarKey"];

[request startAsynchronous];

}

The first time i call -sendRequest, request will be nil. That should be fine. Any time after the first that I call it, the first two lines should reset the request correctly, right?

Also, does ASIHTTPRequest have an instance method that does:

[request clearDelegatesAndCancel];

[request release];

Or, should I just create an ASIHTTPRequest category and define a method that does the above?

I'm asking because I want to write this code in four spots: dealloc, sendRequest, requestFinished, and requestFailed.

Wait, if I call [request release] will that call my delegate and/or queue’s failure delegate methods like [request cancel] does? If not, then can I just do [request release] in sendRequest, requestFinished, and requestFailed; and do both [request clearDelegatesAndCancel] and then [request release] in dealloc?

答:

You must call cancel and clear the delegate before you release your reference to the request. Calling release will not cause the request to immediately stop, so the delegate may be called later on (by which time it might not exist).

I'm on an older version, but I do:

request.delegate = nil; // after this line there are guaranteed to be no more calls to delegate
[request cancel];
[request release];

未验证:留着慢慢看 http://blog.csdn.net/proteas/article/details/7226173

近期将xcode升级到了4.2,SDK是 iOS5。在 iOS 5 下,以前可以正常工作的 NSOperation,会崩溃。崩溃的原因是:取消队列中的操作,但是该操作还没有开始。

解决这个问题的方法是:

在 start 方法中判断操作是否已经取消,如果取消,结束操作,没有取消,再执行操作。

在 cancel 方法中判断操作是否正在执行,如果在执行,结束操作,如果没有,修改操作的isCancelled状态。

头文件:

[cpp]  view plain copy
  1. #import <Foundation/Foundation.h>
  2. @interface FMURLRequest : NSOperation {
  3. BOOL _isReady;
  4. BOOL _isCancelled;
  5. BOOL _isExecuting;
  6. BOOL _isFinished;
  7. }
  8. - (void)cancel;
  9. @end

实现文件:

[cpp]  view plain copy
  1. #import "FMURLRequest.h"
  2. @interface FMURLRequest ()
  3. - (BOOL)isReady;
  4. - (BOOL)isExecuting;
  5. - (BOOL)isFinished;
  6. - (BOOL)isCancelled;
  7. - (BOOL)isConcurrent;
  8. - (void)start;
  9. - (void)finish;
  10. @end
  11. @implementation FMURLRequest
  12. - (id)init {
  13. if ((self = [super init])) {
  14. _isCancelled = NO;
  15. _isExecuting = NO;
  16. _isFinished = NO;
  17. _isReady = YES;
  18. }
  19. return self;
  20. }
  21. - (void)dealloc {
  22. [super dealloc];
  23. }
  24. #pragma -
  25. #pragma mark Operation Management & Super Class Methods
  26. - (BOOL)isReady {
  27. return _isReady;
  28. }
  29. - (BOOL)isExecuting {
  30. return _isExecuting;
  31. }
  32. - (BOOL)isFinished {
  33. return _isFinished;
  34. }
  35. - (BOOL)isCancelled {
  36. return _isCancelled;
  37. }
  38. - (BOOL)isConcurrent {
  39. return YES;
  40. }
  41. - (void)start {
  42. if (![NSThread isMainThread]) {
  43. [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
  44. return;
  45. }
  46. [self willChangeValueForKey:@"isExecuting"];
  47. _isExecuting = YES;
  48. [self didChangeValueForKey:@"isExecuting"];
  49. if ([self isCancelled]) {
  50. [self finish];
  51. return;
  52. }
  53. // TODO: start operation
  54. }
  55. - (void)finish {
  56. [self willChangeValueForKey:@"isExecuting"];
  57. [self willChangeValueForKey:@"isFinished"];
  58. _isExecuting = NO;
  59. _isFinished = YES;
  60. [self didChangeValueForKey:@"isExecuting"];
  61. [self didChangeValueForKey:@"isFinished"];
  62. }
  63. - (void)cancel {
  64. [self willChangeValueForKey:@"isCancelled"];
  65. _isCancelled = YES;
  66. [self didChangeValueForKey:@"isCancelled"];
  67. if ([self isExecuting] == YES) {
  68. // TODO: clean resource
  69. [self finish];
  70. }
  71. }
  72. @end
NSOperation class
The NSOperation class is an abstract class you use to encapsulate the code and data associated with a single task.Because it is abstract, you do not use this class directly but instead subclass or use one of the system-defined subclasses (NSInvocationOperation orNSBlockOperation) to perform the actual task.An operation object is a single-shot object—that is, it executes its task once and cannot be used to execute it again.You typically execute operations by adding them to an operation queue (an instance of the NSOperationQueue class).An operation queue executes its operations either directly, by running them on secondary threads, or indirectly using the libdispatch libraryIf you do not want to use an operation queue, you can execute an operation yourself by calling its start method directly from your code. Executing operations manually does put more of a burden on your code, because starting an operation that is not in the ready state triggers an exception. The isReady method reports on the operation’s readiness.  key-value coding (KVC) and key-value observing (KVO)
Concurrent(并发) versus Non-Concurrent
If you plan on executing an operation object manually, instead of adding it to a queue, you can design your operation to execute in a concurrent or non-concurrent manner. Operation objects are non-concurrent by default. In a non-concurrent operation, the operation’s task is performed synchronously—that is, the operation object does not create a separate thread on which to run the task. Thus, when you call the start method of a non-concurrent operation directly from your code, the operation executes immediately in the current thread. By the time the start method of such an object returns control to the caller, the task itself is complete.
In contrast to a non-concurrent operation, which runs synchronously, a concurrent operation runs asynchronously. In other words, when you call the start method of a concurrent operation, that method could return before the corresponding task is completed. This might happen because the operation object created a new thread to execute the task or because the operation called an asynchronous function. It does not actually matter if the operation is ongoing when control returns to the caller, only that it could be ongoing.
If you always plan to use queues to execute your operations, it is simpler to define them as non-concurrent. If you execute operations manually, though, you might want to define your operation objects as concurrent to ensure that they always execute asynchronously. Defining a concurrent operation requires more work, because you have to monitor the ongoing state of your task and report changes in that state using KVO notifications. But defining concurrent operations can be useful in cases where you want to ensure that a manually executed operation does not block the calling thread.
For non-concurrent operations, you typically override only one method:
main
Into this method, you place the code needed to perform the given task. Of course, you should also define a custom initialization method to make it easier to create instances of your custom class. You might also want to define getter and setter methods to access the data from the operation. However, if you do define custom getter and setter methods, you must make sure those methods can be called safely from multiple threads.
If you are creating a concurrent operation, you need to override the following methods at a minimum:
start
isConcurrent
isExecuting
isFinished  - (void)start
Begins the execution of the operation.
The default implementation of this method updates the execution state of the operation and calls the receiver’s main method. This method also performs several checks to ensure that the operation can actually run.  - (void)main
Performs the receiver’s non-concurrent task.
The default implementation of this method does nothing. You should override this method to perform the desired task. In your implementation, do not invoke super.If you are implementing a concurrent operation, you are not required to override this method but may do so if you plan to call it from your custom start method.  NSOperationQueue
The NSOperationQueue class regulates the execution of a set of NSOperation objects. After being added to a queue, an operation remains in that queue until it is explicitly canceled or finishes executing its task.You cannot directly remove an operation from a queue after it has been added. An operation remains in its queue until it reports that it is finished with its task. 

转载于:https://www.cnblogs.com/snake-hand/p/3144858.html

operation is executing and cannot be enqueued相关推荐

  1. 关于mysql的ddl_log.log文件

    今天在mysql数据库的data目录下发现了这样的一个log文件 ddl_log.log 于是官网查看了一下,英文好的可以自己阅读一下,不好的就麻烦了:( The DDL Log The DDL lo ...

  2. java 条件变量_Windows下条件变量的实现

    条件变量是什么? 是一种同步对象. 条件变量有什么用? 用于复杂的.多线程的.多核的程序中,实现多个线程间同步任务. 条件变量与其它同步对象的区别? 与事件.互斥锁.segment等同步对象相比,条件 ...

  3. The App Launch Cycle

    When your app is launched, it moves from the not running state to the active or background state, tr ...

  4. what is completion

    struct completion: 有的时候我们需要在一个线程里面发起另外一个线程里的某些动作,然后等待另外一个线程的动作完成.这个我们可以用completion.这是信号量的一种简单实现. 完成变 ...

  5. ATmega32U4 芯片介绍 相关开源应用

    网址: https://www.microchip.com/wwwproducts/en/atmega32u4 Summary The low-power Microchip 8-bit AVR RI ...

  6. 附录:ARM 手册 词汇表

    来自:<DDI0406C_C_arm_architecture_reference_manual.pdf>p2723 能够查询到:"RAZ RAO WI 等的意思" R ...

  7. 安装Pod时提示ERROR: While executing gem ... (Errno::EPERM) Operation not permitted - /usr/bin/pod...

    环境:OSX EI 10.11.1 昨天切换gem源后,招待pod安装没有任何问题,也可以正常用$ gem sources --add https://ruby.taobao.org/ --remov ...

  8. 安装pod遇到这种错误ERROR: While executing gem ... (Errno::EPERM) Operation not permitted - /usr/bin/xco

    安装pod 遇到这种错误 ERROR:  While executing gem ... (Errno::EPERM)     Operation not permitted - /usr/bin/x ...

  9. 终端中出现While executing gem ... (Errno::EPERM) Operation not permitted - /usr/bin/pod错误的修改方法...

    把输入终端的sudo gem install cocoapods改为 sudo gem install -n /usr/local/bin/ cocoapods即可 转载于:https://www.c ...

  10. Operation Queues并发编程

    并发.异步在我们的编程中,见到的太多了.在iOS中,实现并发的主要三个途径Operation Queues.Dispatch Queues.Dispatch Sources,今天我们就来详细介绍Ope ...

最新文章

  1. 如何部署 Hyperic ,使得从内网监测外网服务器
  2. oracle 10g的闪回删除与回收站
  3. OrCAD Capture CIS 16.6 修改原理图的页面大小
  4. python的第三方库是干什么用的-Python最强大的第三方库,你有必要了解一下!
  5. 计算机科技的主题,科技感十足的电脑桌面,私藏多年,60多个主题和皮肤统统给大家...
  6. 平面上两条直线的夹角
  7. 计算机设备管理器驱动,设备管理器安装驱动程序的详细教程
  8. validation注解
  9. mac 下使用ssh
  10. python 判断大于等于且小于等于_关于if语句:检查python中值是否大于、小于或等于零的更好方法...
  11. python中复数的乘法_不一致的numpy复数乘法结果
  12. 如何理解卷积:信号处理、图像处理中的应用
  13. base64编码类------原始码(C#)
  14. 0.爬虫介绍及requests库的使用
  15. Media.Metrics简介
  16. 海伦司圆梦上市:徐炳忠身价超过奈雪的茶掌门人,未来能否坚挺?
  17. php用户名不能以数字开头,不能以数字开头命名CSS类
  18. 校园人到企业人的转变
  19. 如何将手机wifi网络通过USB共享给电脑使用
  20. [80一代]关于垮掉的一代

热门文章

  1. nvcc-V 程序“nvcc”尚未安装。 您可以使用以下命令安装: sudo apt install nvidia-cuda-toolkit
  2. Tensorflow教程2:使用卷积神经网络的图像分类器
  3. SQLServer数据库中截取字符串的常用方法
  4. python求解LeetCode题目,找出数组中的Majority element元素
  5. cognos数据源配置修改oracle,Cognos 新建数据源报错(原创)
  6. 启动win内linux系统吗,现在装的是linux系统,在未使用的分区内又装一个win7系统,但是启动时只有一个window系统是为什么??...
  7. python 倒计时功能怎么用print实现_在python中的print语句中实现60秒倒计时
  8. Java 多维数组 三维数组 初始化 赋值 打印
  9. 历史学与计算机科学交叉学科,药学与其他学科的交叉学科有哪些?需要学习什么课..._药学职称考试_帮考网...
  10. JavaSE基础——Map集合、 Collections(集合工具类)