我正在一项行动中执行一项长期任务,我希望能够显示我所在的位置。为此,我创建了一个文本字段,我尝试使用setStringValue:
[textField setStingValue: [NSSting stringWithFormat:@"%ld",currentValue]]
代码可以正常工作,但不幸的是,它不会在每次迭代后更新NSTextField,而是在整个Action完成时更新。
我做错了什么?
答案 0 :(得分:2)
这是因为使用Cocoa框架的应用程序使用事件循环来执行操作,并且事件以完全连续的方式发生。
事件基本上是框架设计者无法预测或发现以延迟方式运行的任何类型的操作。由于您无法预测何时执行点击,因此需要将其视为事件;并且出于效率原因(因为如果您不需要,您不想多次重新绘制组件),重绘操作也是事件。
您的操作是为响应用户事件而运行的(例如,单击按钮是一个事件),因此会阻止队列中等待的所有其他事件,直到完成为止。但是,组件会重新绘制以响应不同的框架触发事件,因此文本字段必须等到操作完成后重新绘制自身。这就是为什么您无法从操作中直观地更改文本字段的值。
为了通知您的用户任务进度,您需要在另一个线程上运行它。关于线程有一个很多,所以你应该阅读一些关于它们的内容。我也确信有很多关于如何在后台线程中运行长动作的示例,并相应地为整个Internet上的Cocoa更新UI。
答案 1 :(得分:1)
当您单击UI组件并进入Action块时,代码将在主线程上运行,该线程与绘制UI的线程相同。如果你在那个块中运行一个长时间运行的操作,那么在你完成之后它就不会画画,因为它正忙于做你做的任何事情 - 你已经劫持了绘制线程。
正如其他地方所说,你需要生成另一个线程,然后让新线程执行长时间运行的操作,偶尔发送消息让主线程更新UI。
下一步,请阅读NSThread上的Apple文档,具体为:
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
请注意,线程是一个非平凡的域名区域,如果您不小心,可以为某些奇怪的行为做好准备。