NSOperation阻止UI绘画?
我在使用NSOperation
和绘图之后有一些build议:
我有一个主线程创build我的NSOperation
子类,然后将其添加到NSOperationQueue
。
我的NSOperation
做了一些繁重的处理,它打算在main()方法中循环几分钟,不断地处理一些工作,但是现在我只是有一个while()循环,里面有一个sleep(1),它被设置为5次左右(testing)。
产生这个NSOperation
的主(原始)线程负责绘制到视图和更新UI。
我打算让NSOperation线程使用一个通知来告诉主线程它已经完成了一些处理,现在这个通知每一次发送一次,通过它的while()循环发送一次(也就是每秒一次,因为它只是在睡觉(1))。 主线程(视图),注册以接收这些通知。
通知立即通过主线程,看起来asynchronous,看起来很好。 看来,两个线程按预期运行…这是 – 同时。 (我使用NSLog()只是大致检查每个线程发送和接收通知)。
当视图接收到一个通知,并且它的处理方法被调用时,我只需递增一个整型variables,然后试着将其绘制到视图中(作为一个当然的string)。 在testing中,drawRect中的代码:将这个整数(作为string)绘制到屏幕上。
然而,这里是我的问题(对不起,需要一点时间来到这里):当主线程(视图)从NSOperation接收到通知时,它更新此testing整数并调用[self setNeedsDisplay]。 但是,直到NSOperation完成之后,视图才会重绘! 我期望NSOperation,作为一个单独的线程,将无法阻止主线程的事件循环,但似乎这是发生了什么事情。 当NSOperation完成并且它的main()返回时,视图最终重新绘制自己。
也许我没有正确使用NSOperation
。 我在“非并发”模式下使用它,但尽pipe名字我的理解是,这仍然产生一个新的线程,并允许asynchronous处理。
任何帮助或build议非常感谢,如果你想看到一些代码只是让我知道。
主线程上没有执行观察者中响应您的通知而执行的方法。
因此,在该方法中,可以使用performSelectorOnMainThread:withObject:waitUntilDone:
强制另一个方法在主线程上运行。
例如:
MyOperation.m
- (void)main { for (int i = 1; i <= 5; i++) { sleep(1); [[NSNotificationCenter defaultCenter] postNotificationName:@"GTCNotification" object:[NSNumber numberWithInteger:i]]; } }
MyViewController.m
- (void)setupOperation { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myNotificationResponse:) name:@"GTCNotification" object:nil]; NSOperationQueue *opQueue = [[NSOperationQueue alloc] init]; MyOperation *myOp = [[MyOperation alloc] init]; [opQueue addOperation:myOp]; [myOp release]; [opQueue release]; } - (void)myNotificationResponse:(NSNotification*)note { NSNumber *count = [note object]; [self performSelectorOnMainThread:@selector(updateView:) withObject:count waitUntilDone:YES]; } - (void)updateView:(NSNumber*)count { countLabel.text = count.stringValue; }
大多数人都知道,任何与显示相关的任务都必须在主线程上完成。 但是,直接的结果是,对可能影响绘图的Cocoa绑定属性的任何更改也必须在主线程上修改(因为KVO触发器将在触发它们的线程上处理)。 这对大多数人来说是一个惊喜:特别是从主线程以外的线程调用[self setNeedsDisplay]是不安全的。
正如gerry所提到的,你的NSNotification不在主线程上处理,而是在它发送的线程上处理。 因此,在您的NSNotification处理程序中,如果它们与显示相关或者它们影响cocoa绑定,则必须将您的命令发送回主线程。 @performSelector工作,但与队列,我发现一个更容易和更可读的方法:
[ [ NSOperationQueue mainQueue] addOperationWithBlock:^(void) { /* Your main-thread code here */ }];
它避免了辅助函数的定义,它的唯一目的是从主线程调用。 mainQueue仅在> 10.6中定义。
- 自动布局UILabels
- 为什么不设置这个UISlider的值属性更新其位置?
- 确定一个单元格的当前状态
- 不在背景上调用CLLocationManager委托方法
- 核心数据:从多个实体或关系获取结果
- 在iOS中将HTMLstring下载到NSString或Swiftstringvariables中
- iOS是否查找特定于地区的.lproj目录(例如en_US.lproj)?
- 无法将types'CFString'的值转换为期望的参数types'UnsafePointer <Void>'(又名'UnsafePointer <()>')
- Xcode 4和Interface Builder:编辑垂直间距约束(Anchor Top,而不是Bottom)