2012-03-20 7 views
1

アプリケーションの実行中にログを表示できる端末のようなアプリケーションを作成しようとしています。アップデートのサイズと頻度に関するNSTextStorageの制限

現在の実装では、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 

答えて

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

私は実際に元のコードでマルチスレッドについて考えました。そのため、関数フィードでdispatch_asyncを使用するときにシリアルキューを追加しました。私はこのシリアルキューが1つのブロックで1ブロック処理されると仮定しますか?私はまだobjcとGCDを初めて使っています。しかし、元のコードがパラレル以外のシリアルで実際に動作しているわけではありません。私は少し混乱しています。 –

+0

あなたのコードは* a *シリアルキューで実行されていましたが、AppKitが使用するのと同じ*キューではありませんでした。それには 'dispatch_async(dispatch_get_main_queue()、...)'を使います。 –

+0

ああ、ありがとうございました。 –

関連する問題