NSOperation在执行时失败(NSOperation fails on execution)

编程入门 行业动态 更新时间:2024-10-23 23:32:33
NSOperation在执行时失败(NSOperation fails on execution)

我对NSOperations有疑问。 一切正常,但有时(我不知道为什么)操作块被简单地跳过。 我错过了什么吗? 怎么可能操作甚至不是NSLogging“操作输入”? 以下是viewDidLoad中的一些代码:

//I'm using weakOperation in order to make [self.queue cancelAllOperation] method when viewWillDisappear NSBlockOperation* operation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation* weakOperation = operation; NSString *session=@""; @try{ session = [self getSessionId];//getting data from CoreData }@catch(NSException *e) { NSLog(@"EXCEPTION WITH SESSION"); } weakOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operation entered"); [self downloadJSONArray]; //doing some connection downloading and using session [self downloadImages]; //downloading images from urls from JSONs [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread } } [self.queue addOperation:weakOperation];

什么可能是coul跳过这个块?

是否在iOS中创建了最大线程数?

编辑 :嘿,我已经找到了为什么会发生这种情况 - 当很多应用程序在后台运行并且iOS没有资源来排队另一个线程时它只是跳过它,如何在这种情况下表现?

I have problem with NSOperations. Everything works fine but sometimes (I don't know why) Operation block is simply skipped. Am I missing something? How is it possible that operation is not even NSLogging "operation entered"? Here is some code from viewDidLoad:

//I'm using weakOperation in order to make [self.queue cancelAllOperation] method when viewWillDisappear NSBlockOperation* operation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation* weakOperation = operation; NSString *session=@""; @try{ session = [self getSessionId];//getting data from CoreData }@catch(NSException *e) { NSLog(@"EXCEPTION WITH SESSION"); } weakOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operation entered"); [self downloadJSONArray]; //doing some connection downloading and using session [self downloadImages]; //downloading images from urls from JSONs [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread } } [self.queue addOperation:weakOperation];

What could be scenario that coul make skip this block ?

Is there max number of threads created in iOS?

EDIT: Hey, I'have found why this happends - when a lot of applications run in the background and iOS does not have resources to queue another thread it simply skips that, how to behave in this situation?

最满意答案

您正在为弱变量分配新的NSBlockOperation 。 无论何时将新对象分配给弱变量,都有可能立即释放它。

如果需要对操作的弱引用,则首先将对象分配给某个局部变量,然后获取该对象的弱引用:

NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operation entered"); [self downloadJSONArray]; //doing some connection downloading and using session [self downloadImages]; //downloading images from urls from JSONs [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread } } __weak NSBlockOperation* weakOperation = operation; [self.queue addOperation:weakOperation];

但是,正如该方法所示, weakOperation是不必要的。 您通常只需要弱引用以避免强引用周期。 但目前没有这样的循环,所以你可以这样做:

NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operation entered"); [self downloadJSONArray]; //doing some connection downloading and using session [self downloadImages]; //downloading images from urls from JSONs [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread } } [self.queue addOperation:operation];

查看代码注释,你会说“我正在使用weakOperation ,以便在viewWillDisappear时使用[self.queue cancelAllOperation]方法”。 像这样使用weakOperation将无法实现您想要的效果,因为您的操作不会检查它是否被取消,因此当NSOperationQueue尝试取消它时它不会响应。

如果你想这样做,那么你的weakOperation模式的变化可能很有用,但是你可以使用块中的弱引用来检查操作是否被取消,而不是使用这个weakOperation将它添加到队列中。并且您希望块中的弱引用以避免块本身保留操作,从而导致强引用周期)。 另一个关键的观察是,不是创建新的NSBlockOperation ,只需将执行块添加到您创建的原始操作:

NSBlockOperation* operation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation* weakOperation = operation; [operation addExecutionBlock:^{ NSLog(@"operation entered"); if ([weakOperation isCancelled]) return; [self downloadJSONArray]; //doing some connection downloading and using session if ([weakOperation isCancelled]) return; [self downloadImages]; //downloading images from urls from JSONs if ([weakOperation isCancelled]) return; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread }]; }]; [self.queue addOperation:operation];

显然,如果操作在downloadJSONArray或downloadImages被绑定,则在从这些方法返回之前,它不会响应取消事件。 如果您希望此操作能够合理快速地响应取消事件,则必须使用这些方法检查取消状态。


在回答你的第二个问题时,是的,有一个最大线程数,但它是一个相当大的数字,并且还有其他因素在线程数成为问题之前发挥作用。 约束因素可能是downloadImages方法(因为您只能有5个并发下载请求)。 即使这不是问题,您也希望限制并发操作的数量,以减轻应用程序的峰值内存使用量。 如果涉及任何网络操作,您通常希望执行以下操作:

self.queue.maxConcurrentOperationCount = 4; // or 5

这样,您可以最小化您使用的有限系统资源(包括线程)的数量。

顺便说一下,我假设downloadJSONArray和downloadImages是同步方法。 如果这些请求正在执行异步网络请求,您可能需要考虑进一步重构代码以确保操作不会过早完成(例如,将其包装在并发的NSOperation子类中或将这些方法更改为同步运行)。

You are assigning a new NSBlockOperation to a weak variable. Whenever you assign a new object to a weak variable, you risk having it released immediately.

If you needed a weak reference to the operation, you'd assign the object to some local variable first, and then get the weak reference for that object:

NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operation entered"); [self downloadJSONArray]; //doing some connection downloading and using session [self downloadImages]; //downloading images from urls from JSONs [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread } } __weak NSBlockOperation* weakOperation = operation; [self.queue addOperation:weakOperation];

But, as the method stands, the weakOperation is unnecessary. You generally only need weak references to avoid strong reference cycles. But no such cycle is present currently, so you can just do:

NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operation entered"); [self downloadJSONArray]; //doing some connection downloading and using session [self downloadImages]; //downloading images from urls from JSONs [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread } } [self.queue addOperation:operation];

Looking at your code comment, you say "I'm using weakOperation in order to make [self.queue cancelAllOperation] method when viewWillDisappear". Using weakOperation like this will not accomplish what you want because your operation is not checking to see if it was canceled and thus it will not respond when the NSOperationQueue tries to cancel it.

If you wanted to do that, then a variation on your weakOperation pattern can be useful, but rather than using this weakOperation to add it to the queue, you can use the weak reference within the block to check to see if the operation was canceled (and you want the weak reference in the block to avoid the block from retaining the operation, itself, causing a strong reference cycle). The other key observation is that rather than creating a new NSBlockOperation, simply add an execution block to the original operation you created:

NSBlockOperation* operation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation* weakOperation = operation; [operation addExecutionBlock:^{ NSLog(@"operation entered"); if ([weakOperation isCancelled]) return; [self downloadJSONArray]; //doing some connection downloading and using session if ([weakOperation isCancelled]) return; [self downloadImages]; //downloading images from urls from JSONs if ([weakOperation isCancelled]) return; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self refresh]; //update mainThread }]; }]; [self.queue addOperation:operation];

Clearly, if the operation is tied up in downloadJSONArray or downloadImages, it won't respond to the cancelation event until it returns from those methods. You'd have to check the cancelation status with those methods, too, if you want this operation to respond reasonably quickly to the cancellation event.


In answer to your second question, yes, there is a maximum number of threads, but it's a reasonably large number and there are other factors that come into play before the number of threads becomes an issue. The constraining factor is likely to be the downloadImages method (as you can only have 5 concurrent download requests). And even if that wasn't an issue, you'd want to constrain the number of concurrent operations, anyway, to mitigate the app's peak memory usage. If there are any network operations involved, you generally want to do something like:

self.queue.maxConcurrentOperationCount = 4; // or 5

That way, you minimize how much of the limited system resources (including threads) you are using.

By the way, I assume that downloadJSONArray and downloadImages are synchronous methods. If those are performing asynchronous network requests, you might want to consider further refactoring of the code to ensure the operation doesn't complete prematurely (e.g. wrap this in a concurrent NSOperation subclass or change those methods to run synchronously).

更多推荐

self,iOS,weakOperation,operation,queue,电脑培训,计算机培训,IT培训"/> <meta n

本文发布于:2023-07-30 22:16:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1340332.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:NSOperation   fails   execution

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!