Objective c NSTextStorage对更新大小和频率的限制
我正在尝试创建一个类似终端的应用程序,它可以在应用程序运行时显示日志 当前实现使用NSScrollView->NSTextView。但是,我注意到NSTextView的大小对于我的程序来说不够大,并且我不能非常频繁地更新UI 假设我们有下面这样的示例代码(其他所有代码都与全新的Xcode应用程序项目保持相同) 程序继续每隔0.1秒向UI打印一些垃圾文本,并更新视图。我发现程序每次运行大约4分钟后就会崩溃。此外,我还必须在每个垃圾文本之间添加0.1秒的延迟。如果我没有延迟任何时间,程序就会立即崩溃。我想找到解决这个问题的方法 我不确定NSTextView是否仍然是我的应用程序的好选择。如果没有,谁能给我指出正确的方向,哪一个视图或视图集合可以像终端应用程序一样工作 提前谢谢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秒的延迟。如果我没有延迟任何时间,程序就会立即崩溃
#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(),…)
。