operation is executing and cannot be enqueued

作为依赖关系的另一个 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 {

[requestclearDelegatesAndCancel];

[requestrelease];

[superdealloc];

}

- (void)sendRequest {

[requestclearDelegatesAndCancel];

[requestrelease];

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

request= [[ASIFormDataRequestalloc]initWithURL:url];

[urlrelease];

request.delegate=self;

[requestsetPostValue:@"value1"forKey:@"key1"];

[requestsetPostValue:@"value2"forKey:@"key2"];

[requestsetPostValue:sessionforKey:@"iVarKey"];

[requeststartAsynchronous];

}

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:

[requestclearDelegatesAndCancel];

[requestrelease];

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 [requestclearDelegatesAndCancel] 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.youkuaiyun.com/proteas/article/details/7226173

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

解决这个问题的方法是:

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

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

头文件:

  1. #import<Foundation/Foundation.h>
  2. @interfaceFMURLRequest:NSOperation{
  3. BOOL_isReady;
  4. BOOL_isCancelled;
  5. BOOL_isExecuting;
  6. BOOL_isFinished;
  7. }
  8. -(void)cancel;
  9. @end


实现文件:

  1. #import"FMURLRequest.h"
  2. @interfaceFMURLRequest()
  3. -(BOOL)isReady;
  4. -(BOOL)isExecuting;
  5. -(BOOL)isFinished;
  6. -(BOOL)isCancelled;
  7. -(BOOL)isConcurrent;
  8. -(void)start;
  9. -(void)finish;
  10. @end
  11. @implementationFMURLRequest
  12. -(id)init{
  13. if((self=[superinit])){
  14. _isCancelled=NO;
  15. _isExecuting=NO;
  16. _isFinished=NO;
  17. _isReady=YES;
  18. }
  19. returnself;
  20. }
  21. -(void)dealloc{
  22. [superdealloc];
  23. }
  24. #pragma-
  25. #pragmamarkOperationManagement&SuperClassMethods
  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. returnYES;
  40. }
  41. -(void)start{
  42. if(![NSThreadisMainThread]){
  43. [selfperformSelectorOnMainThread:@selector(start)withObject:nilwaitUntilDone:NO];
  44. return;
  45. }
  46. [selfwillChangeValueForKey:@"isExecuting"];
  47. _isExecuting=YES;
  48. [selfdidChangeValueForKey:@"isExecuting"];
  49. if([selfisCancelled]){
  50. [selffinish];
  51. return;
  52. }
  53. //TODO:startoperation
  54. }
  55. -(void)finish{
  56. [selfwillChangeValueForKey:@"isExecuting"];
  57. [selfwillChangeValueForKey:@"isFinished"];
  58. _isExecuting=NO;
  59. _isFinished=YES;
  60. [selfdidChangeValueForKey:@"isExecuting"];
  61. [selfdidChangeValueForKey:@"isFinished"];
  62. }
  63. -(void)cancel{
  64. [selfwillChangeValueForKey:@"isCancelled"];
  65. _isCancelled=YES;
  66. [selfdidChangeValueForKey:@"isCancelled"];
  67. if([selfisExecuting]==YES){
  68. //TODO:cleanresource
  69. [selffinish];
  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. 
### 解决方案分析 在移动开发中遇到 `username cannot be resolved or is not a field` 错误通常表明代码尝试访问的对象或字段未被正确定义或初始化。以下是可能的原因及其解决方案: #### 1. 数据库查询中的字段定义问题 如果错误发生在数据库操作阶段,可能是 SQL 查询语句中指定的字段名不存在于目标表中。例如,在执行如下查询时: ```javascript const id = 223; connection.query('SELECT * FROM todos WHERE id = ?', [id], (error, todos, fields) => { if (error) { console.error('An error occurred while executing the query'); throw error; } console.log(todos); }); ``` 上述代码片段展示了如何通过参数化查询防止 SQL 注入攻击[^1]。然而,如果查询的目标表缺少名为 `username` 的列,则会引发类似的解析错误。 **解决方法:** - 验证数据库模式,确认目标表确实包含 `username` 字段。 - 如果该字段缺失,需更新数据库结构并重新部署应用。 #### 2. 对象属性引用不匹配 当程序试图访问对象的一个属性而该属性并未声明时也会触发此错误。例如,假设有一个 JSON 响应数据: ```json { "userId": 1, "name": "John Doe" } ``` 如果代码写成 `response.username` 而不是 `response.name` 或其他实际存在的键值对,则会出现无法解析的情况。 **修正方式:** - 审查 API 返回的数据模型,确保所调用的属性名称与返回结果一致。 - 使用条件判断来处理潜在的 null 或 undefined 属性情况,比如 JavaScript 中可以采用可选链语法 (`?.`) 来安全地访问深层嵌套属性。 #### 3. 编译器/解释器环境配置不当 有时,IDE 或构建工具未能正确加载依赖项也可能导致此类假阳性警告消息。这尤其常见于跨平台框架项目里(如 React Native、Flutter 等),其中某些插件或者包版本冲突会影响全局命名空间识别准确性。 **建议措施:** - 清理缓存文件夹后再重建工程; - 更新至最新稳定版 SDK 和第三方库组合; - 参考官方文档调整 Gradle/Maven/Podfile 设置以兼容特定功能需求。 ```bash # For Android Studio projects using Gradle build system: ./gradlew clean assembleDebug --refresh-dependencies ``` ### 结论 综上所述,针对 `'username cannot be resolved or is not a field'` 这一异常现象可以从以上三个方面逐一排查原因,并采取相应对策加以修复。值得注意的是,虽然文中提到的游戏规则变更案例涉及到了法律层面考量[^2],但它并不直接影响技术实现细节上的讨论方向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值