我正在尝试创建一个类似于应用程序的终端,可以在应用程序运行时显示日志。
当前实现使用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
答案 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];
}