Objective c NSTextStorage对更新大小和频率的限制

Objective c NSTextStorage对更新大小和频率的限制,objective-c,xcode,macos,user-interface,Objective C,Xcode,Macos,User Interface,我正在尝试创建一个类似终端的应用程序,它可以在应用程序运行时显示日志 当前实现使用NSScrollView->NSTextView。但是,我注意到NSTextView的大小对于我的程序来说不够大,并且我不能非常频繁地更新UI 假设我们有下面这样的示例代码(其他所有代码都与全新的Xcode应用程序项目保持相同) 程序继续每隔0.1秒向UI打印一些垃圾文本,并更新视图。我发现程序每次运行大约4分钟后就会崩溃。此外,我还必须在每个垃圾文本之间添加0.1秒的延迟。如果我没有延迟任何时间,程序就会立即崩溃

我正在尝试创建一个类似终端的应用程序,它可以在应用程序运行时显示日志

当前实现使用NSScrollView->NSTextView。但是,我注意到NSTextView的大小对于我的程序来说不够大,并且我不能非常频繁地更新UI

假设我们有下面这样的示例代码(其他所有代码都与全新的Xcode应用程序项目保持相同)

程序继续每隔0.1秒向UI打印一些垃圾文本,并更新视图。我发现程序每次运行大约4分钟后就会崩溃。此外,我还必须在每个垃圾文本之间添加0.1秒的延迟。如果我没有延迟任何时间,程序就会立即崩溃。我想找到解决这个问题的方法

我不确定NSTextView是否仍然是我的应用程序的好选择。如果没有,谁能给我指出正确的方向,哪一个视图或视图集合可以像终端应用程序一样工作

提前谢谢

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize queue = _queue;
@synthesize theTextView = _theTextView;

- (void)dealloc
{
    [super dealloc];
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application 322, 40, 895, 720
    NSScrollView *scrollview = [[NSScrollView alloc]
                                initWithFrame:[[_window contentView] frame]];
    NSSize contentSize = [scrollview contentSize];

    [scrollview setBorderType:NSNoBorder];
    [scrollview setHasVerticalScroller:YES];
    [scrollview setHasHorizontalScroller:NO];
    [scrollview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];

    _theTextView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0,
                                                               contentSize.width, contentSize.height)];
    [_theTextView setMinSize:NSMakeSize(0.0, contentSize.height)];
    [_theTextView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
    [_theTextView setVerticallyResizable:YES];
    [_theTextView setHorizontallyResizable:NO];
    [_theTextView setAutoresizingMask:NSViewWidthSizable];

    [[_theTextView textContainer] setContainerSize:NSMakeSize(contentSize.width, FLT_MAX)];
    [[_theTextView textContainer] setWidthTracksTextView:YES];

    [scrollview setDocumentView:_theTextView];
    [_window setContentView:scrollview];
    [_window makeKeyAndOrderFront:nil];
    [_window makeFirstResponder:_theTextView];

    [[_theTextView enclosingScrollView] setHasHorizontalScroller:YES];
    [_theTextView setHorizontallyResizable:YES];
    [_theTextView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
    [[_theTextView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
    [[_theTextView textContainer] setWidthTracksTextView:NO];
    _queue = dispatch_queue_create("com.example.MyQueue", NULL);

    [self start];
}

- (void) start {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        [self feed];
    });

}
- (void) feed {
    while (1) {
        dispatch_async(_queue, ^(void){
            NSString * displaytext = (NSString *) CFSTR("Testing Line - asdfasdfklqjwer;opfjiasdlk;fjasd\n");

            NSAttributedString *string = [[NSAttributedString alloc] initWithString:displaytext];
            NSLog(@"Output is %@", string);

            //        [[_theTextView textStorage] appendAttributedString:string];

            [[_theTextView textStorage] beginEditing];
            [[_theTextView textStorage] appendAttributedString:string];
            [[_theTextView textStorage] endEditing];
            [_theTextView scrollRangeToVisible:NSMakeRange([[_theTextView string] length], 0)];

            [string release];

        });
        usleep(100000);
    }

}

@end

AppKit通常不是线程安全的。您正在更改文本存储,并从后台线程滚动文本视图——因此,它的工作不一致或崩溃也就不足为奇了

您所演示的只是您不正确地使用了AppKit,而不是NSTextView在您的目的上存在致命缺陷。(它可能仍然存在致命缺陷,但这不是一个很好的理由。)

要正确执行此测试,请执行以下操作:

- (void)start
{
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(feedOne:) userInfo:nil repeats:YES];
}

- (void)feedOne:(NSTimer*)timer
{
    NSString* displaytext = @"Testing Line - asdfasdfklqjwer;opfjiasdlk;fjasd\n";    
    NSAttributedString* string = [[NSAttributedString alloc] initWithString:displaytext];

    [[_theTextView textStorage] beginEditing];
    [[_theTextView textStorage] appendAttributedString:string];
    [[_theTextView textStorage] endEditing];
    [_theTextView scrollRangeToVisible:NSMakeRange([[_theTextView string] length], 0)];

    [string release];
}

实际上,我在原始代码中考虑了多线程。这就是为什么我在函数提要中使用dispatch_async时添加了一个串行队列。我假设这个串行队列会被一块一块地处理?我对objc和GCD还是新手。但是原始代码不是以串行而不是并行的方式运行吗。我有点困惑。您的代码是在串行队列上运行的,但它与AppKit使用的队列不同。为此,您可以使用
dispatch\u async(dispatch\u get\u main\u queue(),…)