English 中文(简体)
NSTextView 在向 USB 设备写入数据时,不会在循环中更新。
原标题:
  • 时间:2008-12-05 07:04:41
  •  标签:

我正在编写一个Objective-C应用程序,它与USB设备通信。该应用程序持续向设备写入某些数据,并在textView中显示写操作的状态,该textView是NSTextView对象。当我从设备获得写操作状态时,在循环中调用- [NSTextView insertText:] 方法。

问题在于 NSTextView 在每次调用“-insertText:”时不会更新。我只有在整个循环执行完毕后才能获得 NSTextView 的全部内容。

我没有看到NSTextView类的适当刷新或更新方法。我该如何同时接收操作状态并更新NSTextView?

- (IBAction)notifyContentHasChanged:(NSInteger) block {
    NSString *str;
    str = [NSString stringWithFormat:@"Block Written Successfully: %d
", block];
    [data insertText:str];
}

- (IBAction)func {
    while(USB_SUCCESS(status))
    {
        printf("
Blocks Written Successfully: %d",BlockCnt);
        [refToSelf notifyContentHasChanged:BlockCnt];
    }
}

请注意,控制台上的printf能够及时更新,但是NSTextView上不会。

问题回答

Mac OS X不会立即将视图中的更改刷新到屏幕上,以避免在这种情况下常见的闪烁和撕裂。这意味着您不能只坐在循环中并执行阻塞操作,同时更新视图;如果您这样做,您的应用程序的人机界面中的任何内容都不会更新,您的应用程序将出现挂起并最终获得旋转光标。

当应用程序在一小段时间后与窗口服务器没有通信时,旋转光标会出现;根据设计,无法抑制它。 它并不意味着“等待”,而是意味着“该应用程序已偏离正常运行”,您应该努力确保它从不出现在您的用户面前。

要在Cocoa中管理阻塞操作,您可以采取以下两种措施之一:

  1. 您可以在后台线程中执行阻塞操作,然后将结果传递给主线程进行更新人机界面。例如,您可以使用 select(2) 和标准的 UNIX 文件 I/O 调用方式进行 I/O 或套接字通信。

  2. 如果有兼容版本,您可以在运行循环(例如主运行循环)上安排操作; 这通常会为您管理阻塞版本操作的后台线程。 例如,NSFileHandle基于文件描述符提供了运行循环兼容的抽象层; NSStream也为套接字通信提供此功能。

你必须使用:

//Creates the background thread.
dispatch_queue_t backgroundQueue = dispatch_queue_create("Network", nil);

To create a new thread. Then, wrap your code in this:

//Runs code in background thread.
dispatch_async(backgroundQueue, ^(void){
    //Code Here.
});

UI的更新应包装在:

//Sends code within the background thread to the main thread.
dispatch_async(dispatch_get_main_queue(), ^(void){
    //Code Here.
});

所以在你的代码中:

- (IBAction)notifyContentHasChanged:(NSInteger) block {
    NSString *str;
    str = [NSString stringWithFormat:@"Block Written Successfully: %d
", block];
    [data insertText:str];
}

- (IBAction)func {
    dispatch_queue_t backgroundQueue = dispatch_queue_create("Network", nil);
    dispatch_async(backgroundQueue, ^(void){
        while(USB_SUCCESS(status))
        {
            printf("
Blocks Written Successfully: %d",BlockCnt);
            dispatch_async(dispatch_get_main_queue(), ^(void){
                [refToSelf notifyContentHasChanged:BlockCnt];
            });
        }
    });
}

你应该能够通过-setNeedsDisplay:方法刷新NSTextView。

我有一个循环在从网络访问数据并将其填充到数据库中。当我处理时,我想要一个类似控制台的窗口(不是Xcode中的窗口,因为这将是一个编译后的应用程序)。

所以我有一个NSTextView,我正在更改其textStorage并在每次循环中向底部滚动。不幸的是,唯一可见的更改发生在循环结束时(尽管正确)。

有没有一种简单的“好的,现在更新屏幕”的方法,而无需进行低级编程或编写更多代码?





相关问题
热门标签