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

时间:2012-03-20 00:50:50

标签: objective-c xcode macos user-interface

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

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

所以我们假设我们有一个如下所示的示例代码,(其他一切都与全新的Xcode APplication项目保持一致)。

程序继续每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

1 个答案:

答案 0 :(得分:3)

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];
}