我刚刚遇到NSOperation的一个奇怪的行为,我修复但不明白.
我按照文档继承了NSOperation.当我使用下面的main方法时,应用程序将使用100%或更多的CPU时间.
-(void)main
{
@try
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
//Cycle forever until told to cancel
while (![self isCancelled])
{
}
[pool release];
}
@catch(...)
{
// Do not rethrow exceptions.
}
//Finish executing
[self completeOperation]; //Send notificatios using KVO
}
Run Code Online (Sandbox Code Playgroud)
相反,当我使用以下主方法时,应用程序使用3%的CPU时间.
-(void)main
{
@try
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
//Create the initial delayed timers
NSTimer *startUpTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:startUpTimer forMode:NSRunLoopCommonModes];
[runLoop run];
//Cycle forever …Run Code Online (Sandbox Code Playgroud) 所以我已经考虑了几天了,我似乎无法找到一个好的方法来使它工作.
我有一个NSOperationQueue只允许一次一个操作.我从文档中了解到:
在OS X v10.6及更高版本中,取消操作会导致操作忽略它可能具有的任何依赖性.此行为使队列可以尽快执行操作的start方法.反过来,start方法将操作移动到完成状态,以便可以从队列中删除它.
当我发送取消时它将设置isCancelled为YES,但我的问题是:
假设我有20个NSOperation队列而且我刚刚取消了18号,它将一直保持NSOperationQueue到它可以运行并说它已经完成(我的NSOperation检查正确isCancelled)但是因为它保留在队列中它也保留在UITableView我设置dataSource的东西中喜欢myOperationQueue.operations.
这就是困扰我的用户,用户将点击Cancel将调用该cancel方法,NSOperation但操作仍会显示,因为它仍然在队列中.
我考虑过start在cancel方法中调用,但不允许只有队列才可以start.
编辑:我也试着重写isFinished的cancel:
[self willChangeValueForKey:@"isFinished"];
_isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
Run Code Online (Sandbox Code Playgroud)
它工作但它也发送start到NSOperation队列中的下一个,它可以导致同时有2个NSOperation,我只想要一个.
在选择要运行的队列dispatch_async时,dispatch_get_global_queue会提到很多.这是一个特殊的后台队列,它将任务委托给某个线程吗?它几乎是一个单身人士吗?
因此,如果我总是将该队列用于我的dispatch_async调用,那么该队列是否会变满并且必须等待其他事情才能启动,或者是否可以将其他任务分配给不同的线程?
我想我有点困惑,因为当我选择队列时NSOperation,我可以选择主线程的队列[NSOperationQueue mainQueue],这似乎是同义词,dispatch_get_main_queue但我在印象背景队列下NSOperation不得不单独制作实例NSOperationQueue但是GCD有一个背景队列单例?(dispatch_get_global_queue)
此外 - 愚蠢的问题,但想确保 - 如果我将一个任务放入队列,队列被分配给一个线程,对吧?如果任务足够大,它就不会在多个线程上拆分,是吗?
multithreading objective-c nsoperation grand-central-dispatch ios
我的代码:
NSOperationQueue *queue;
-(void)viewDidLoad
{
queue = [NSOperationQueue new];
NSOperation* loadImgOp = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(refresh) object:nil];
[queue addOperation:loadImgOp];
}
-(void)refresh
{
[self operationFirst];
[self operationSecond];
...
[self operationFive];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[queue cancelAllOperations];
}
Run Code Online (Sandbox Code Playgroud)
当我调用 new ViewController 时,-(void)refresh 继续工作。cancelAllOperations 不起作用。
请参阅WWDC的视频https://developer.apple.com/videos/play/wwdc2015/226/ 发言人表明我们可以在两个相同类型的NSopeation实例之间添加依赖关系.示例显示警报的NS操作.通过实现这一点,我们可以确保我们不会同时抛出多个警报并使用户烦恼.如果已经显示一个警报,则下一个警报将等待.
我仍然无法弄清楚如何实现NSOperations交叉队列的这种依赖.更简单的话可以任何人展示以下两件事的例子(实现).
1.在队列1的操作A上添加操作B从队列2的依赖性的实现.
2.实现添加相同NSOperation类型的多个实例的依赖关系,即使它们位于不同的队列中.示例:如果我将"AlertOperation"的多个实例添加到不同的队列,我想确保它们之间仍然按顺序进行.
如果示例是在目标C中,我将不胜感激.如有需要,请要求进一步澄清.
我对 NSOperation(现在称为操作)进行了子类化,以在后台执行一些异步查询。我希望一次执行一个。为此,我将 maxConcurrentOperationCount 设置为 1,但它仍然允许队列中存在多个对象。
我已经在类声明的正下方声明了我的队列:
let downloadQueue = OperationQueue()
Run Code Online (Sandbox Code Playgroud)
然后在视图中加载设置了计数:
downloadQueue.maxConcurrentOperationCount = 1
Run Code Online (Sandbox Code Playgroud)
然后在代码中调用Operation子类:
self.downloadQueue.addOperation(DownloadOperation(col: collectionView, index: indexPath, cell: cell))
Run Code Online (Sandbox Code Playgroud)
还有我的子类:
class DownloadOperation : Operation {
var collectionView: UICollectionView
var indexPath: IndexPath
var collectionCell: InnerCollectionCell
init(col: UICollectionView, index: IndexPath, cell: InnerCollectionCell) {
collectionView = col
indexPath = index
collectionCell = cell
}
let mainQueue = OperationQueue.main
override func main() {
if(isCancelled) {
return
}
///
/// Long query that gets objects in background
/// it is itself an async …Run Code Online (Sandbox Code Playgroud) 我已经从网址下载了信息,我将这个网址作为NSOperation在NSOperationQueue中发送,我想知道,如何删除特定的NSOperation以下载特定网址的数据,现在我这样做:
AppDelegate *appController = (AppDelegate *) [[UIApplication sharedApplication] delegate];
for (NSOperation *op in appController.seriesQueue.operations) {
if ([op isKindOfClass:[MyDowndload class]]) {
MyDownload *urlInDownload = (MyDowndload *)op;
if ([urlInDownload.myNew.urlName isEqualToString:[managedObject valueForKey:@"urlName"]] && [urlInDownload.myNew.language isEqualToString:[managedObject valueForKey:@"language"]]) {
[op cancel];
}
}
}
Run Code Online (Sandbox Code Playgroud)
我在tableview中有信息,所以当我为索引路径删除一行时,我输入此检查,并在[op cancel]行中输入,但我可以在控制台日志中看到该线程仍在下载,如何我能停下来删除吗?
我们在我们的应用程序中使用AFNetworking(https://github.com/AFNetworking/AFNetworking)和NSOperationStack(https://github.com/nicklockwood/NSOperationStack)来设置依赖关系,以便最后一次操作优先于队列中的其余操作(堆栈行为).当调用AFURLConnectionOperation的'start'方法时,我遇到了一个问题,但是由于依赖关系,操作的'isReady'方法返回NO.这使得"开始"立即退出.在第一次尝试开始操作之后,'start'方法永远不会被再次调用,因此操作永远不会达到isFinished状态,永远不会从队列中删除,最终操作会阻塞队列.我很感激在这件事上的任何想法.谢谢!
更多信息:没有任何操作被取消,我没有在队列中看到任何依赖关系圈.我们在现有的operationQueue上使用setLIFODependendenciesForOperation而不改变AFNetworking代码:[self.operationQueue setLIFODependendenciesForOperation:operation];
更新:现在,更多地考虑它,是否有可能在一个点上具有零依赖性并且当NSOperationQueue决定操作准备就绪时isReady返回YES,但是,当调用start()时,依赖项的数量变为1或者更多.
我一直在搜索,但只能找到委托模式的想法来传递来自NSOperation的数据.我有一个NSOperation,在完成NSOperation后下载数据我希望它能够传递给将它下载的数据放入NSoperationQueue的类.在我的队列中最多可以有100个这样的NSOPerations,它们都检索唯一的数据.任何想法将不胜感激.
我正在使用enqueueBatchOfHTTPRequestOperations提交一批请求.如果任何请求失败,我想立即取消任何其他仍在进行的请求.为此,我在各个操作上设置故障回调来执行操作[client.operationQueue cancelAllOperations];.
这似乎取消了所有剩余的操作,但它也阻止了批处理的整个completionBlock执行...这是我试图测试此行为的代码(其中一个请求总是在服务器上设置为失败).
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:@"http://arahlf.com"]];
NSMutableArray *requests = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; i++) {
NSURLRequest *request = [client requestWithMethod:@"GET" path:@"echo.php" parameters:@{ @"sleep": @(i) }];
AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:nil failure:nil];
[operation setCompletionBlockWithSuccess:nil failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Request failed, cancelling all operations.");
[client.operationQueue cancelAllOperations];
}];
[requests addObject:operation];
}
[client enqueueBatchOfHTTPRequestOperations:requests progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
NSLog(@"Progress: %i/%i", numberOfFinishedOperations, totalNumberOfOperations);
} completionBlock:^(NSArray *operations) {
NSLog(@"All …Run Code Online (Sandbox Code Playgroud) nsoperation ×10
ios ×6
objective-c ×6
afnetworking ×2
cocoa ×1
iphone ×1
swift ×1
uitableview ×1