通过在主队列上执行的块更新 NSProgressIndicator 时的 CoreAnimation 警告
CoreAnimation warning when updating NSProgressIndicator via a block executed on main queue
我有以下将核心数据实体导出到 JSON 并在这样做时显示进度条的场景。
有时,在导出完成后 sheet 和进度条消失后,我收到以下警告作为控制台消息:
CoreAnimation: warning, deleted thread with uncommitted CATransaction;
set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces.
AppDelegate.m
// AppDelegate.m
- (void)exportAsJSON:(id)sender;
{
NSSavePanel *savePanel = [NSSavePanel savePanel];
[savePanel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
WMJSONExportOperation *operation = nil;
if (result == NSFileHandlingPanelOKButton)
{
[_progressIndicator setDoubleValue:0];
operation = [[WMJSONExportOperation alloc] init];
// setProgressCallbackBlock
[operation setProgressCallbackBlock: ^(double progress) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[_progressIndicator setDoubleValue: progress];
}];
}];
// setExportCompletionBlock
[operation setExportCompletionBlock:^(NSData *data, NSError *error) {
// Insert code here to save data to disk
[_window endSheet:_exportProgressSheet];
}];
[_window beginSheet:_exportProgressSheet completionHandler:^(NSInteger result) {
NSLog(@"ExportProgressSheet completionHandler executed");
}];
NSOperationQueue *queue;
queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
}];
}
WMJSONExportOperation.m, NSOperation 的子类:
- (void)main;
{
NSError *error = nil;
NSData *data = nil;
// just for illustrating the problem:
for (int i=1; i<=10; i++) {
sleep(1);
[self progressCallbackBlock](i * 10);
}
[self exportCompletionBlock](data, error);
}
@end
所以第一个问题是:这只是一个警告,我应该关心吗?
第二个问题,如何避免警告。 SO 上有描述 similar 问题的问题,但建议的解决方案通常是仅从主队列操作 NSProgressIndicator。这不正是我用这段代码所做的吗:
// setProgressCallbackBlock
[operation setProgressCallbackBlock: ^(double progress) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[_progressIndicator setDoubleValue: progress];
}];
}];
在 setting the CA_DEBUG_TRANSACTIONS environment variable 进一步调查消息后,我发现问题不在于发送到 NSProgressIndicator
的消息,而是 sheet 的关闭,我确实做到了从主队列以外的另一个队列触发。
所以这个更改解决了我的问题:
[_window endSheet:_exportProgressSheet];
变成:
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[_window endSheet:_exportProgressSheet];
}];
我有以下将核心数据实体导出到 JSON 并在这样做时显示进度条的场景。
有时,在导出完成后 sheet 和进度条消失后,我收到以下警告作为控制台消息:
CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces.
AppDelegate.m
// AppDelegate.m
- (void)exportAsJSON:(id)sender;
{
NSSavePanel *savePanel = [NSSavePanel savePanel];
[savePanel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
WMJSONExportOperation *operation = nil;
if (result == NSFileHandlingPanelOKButton)
{
[_progressIndicator setDoubleValue:0];
operation = [[WMJSONExportOperation alloc] init];
// setProgressCallbackBlock
[operation setProgressCallbackBlock: ^(double progress) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[_progressIndicator setDoubleValue: progress];
}];
}];
// setExportCompletionBlock
[operation setExportCompletionBlock:^(NSData *data, NSError *error) {
// Insert code here to save data to disk
[_window endSheet:_exportProgressSheet];
}];
[_window beginSheet:_exportProgressSheet completionHandler:^(NSInteger result) {
NSLog(@"ExportProgressSheet completionHandler executed");
}];
NSOperationQueue *queue;
queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
}];
}
WMJSONExportOperation.m, NSOperation 的子类:
- (void)main;
{
NSError *error = nil;
NSData *data = nil;
// just for illustrating the problem:
for (int i=1; i<=10; i++) {
sleep(1);
[self progressCallbackBlock](i * 10);
}
[self exportCompletionBlock](data, error);
}
@end
所以第一个问题是:这只是一个警告,我应该关心吗?
第二个问题,如何避免警告。 SO 上有描述 similar 问题的问题,但建议的解决方案通常是仅从主队列操作 NSProgressIndicator。这不正是我用这段代码所做的吗:
// setProgressCallbackBlock
[operation setProgressCallbackBlock: ^(double progress) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[_progressIndicator setDoubleValue: progress];
}];
}];
在 setting the CA_DEBUG_TRANSACTIONS environment variable 进一步调查消息后,我发现问题不在于发送到 NSProgressIndicator
的消息,而是 sheet 的关闭,我确实做到了从主队列以外的另一个队列触发。
所以这个更改解决了我的问题:
[_window endSheet:_exportProgressSheet];
变成:
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[_window endSheet:_exportProgressSheet];
}];