NSTextStorage ограничение на размер и частоту обновлений
Я пытаюсь создать приложение, подобное терминалу, которое может отображать журналы при запуске приложения.
Текущая реализация использует NSScrollView -> NSTextView. Тем не менее, я заметил, что размер NSTextView недостаточно велик для моей программы, и я не могу обновлять интерфейс очень часто.
Итак, предположим, у нас есть пример кода, подобный приведенному ниже (все остальное остается таким же, как у совершенно нового проекта Xcode APplication).
Программа продолжает выводить текстовый мусор в пользовательский интерфейс каждые 0,1 секунды и обновлять представление. Я обнаружил, что программа вылетает примерно через 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 ответ
В общем, 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];
}