我对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];
可能会有什么方法可以跳过这个区块?
iOS中是否创建了最大线程数?
编辑:嘿,我已经找到了为什么会发生这种情况 - 当很多应用程序在后台运行并且iOS没有资源来排队另一个线程时它只是跳过它,如何在这种情况下表现?
答案 0 :(得分:4)
您正在为弱变量分配新的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
以便在[self.queue cancelAllOperation]
"时制作viewWillDisappear
方法。像这样使用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
相关联,则在从这些方法返回之前,它不会响应取消事件。如果您希望此操作能够合理快速地响应取消事件,您还必须使用这些方法检查取消状态。
在回答你的第二个问题时,是的,有一个最大线程数,但它是一个相当大的数字,并且还有其他因素在线程数成为问题之前发挥作用。约束因子可能是self.queue.maxConcurrentOperationCount = 4; // or 5
方法(因为您只能有5个并发下载请求)。即使这不是一个问题,您也希望限制并发操作的数量,无论如何,以减轻应用程序的峰值内存使用量。如果涉及任何网络操作,您通常需要执行以下操作:
downloadJSONArray
这样,您可以最大限度地减少使用的有限系统资源(包括线程)的数量。
顺便说一下,我假设downloadImages
和NSOperation
是同步方法。如果那些正在执行异步网络请求,您可能需要考虑进一步重构代码以确保操作不会过早完成(例如将其包装在并发{{1}}子类中或更改这些方法以同步运行)