バックグラウンド
私のアプリはネットワークストリームからデータを取り出し、画面上のUI要素の値を変更します。1つの要素はUITextViewであり、受信データの一種のログとして機能します。アプリが着信データの性質を備えた「HasBytesAvailable」NSStreamEventを受信するたびに更新されることになっています。(たとえば、入ってくるデータがケーキに関係している場合、textviewは「6/22/12 8:00-gotcake」のように更新されます)更新方法の例を以下に示します。
[logString insertString:@"This is an update\n" atIndex:0];
//logstring is a MutableString I use to hold my UITextView's text
[logString insertString:timeString atIndex:0]; //timestring is current time
logView.text = logString; //logView is my UITextView
[logView flashScrollIndicators];
//logstring and logview declaration and implementation
@property (nonatomic,retain) IBOutlet UITextView *logView;
@property (nonatomic,retain) NSMutableString *logString;
logString = [[NSMutableString alloc] initWithString:@"-logging started\n"];
問題
TextViewをスクロールしようとしない限り、更新は希望どおりに機能します。ただし、テキストをスクロールして押し続けると、おそらく更新コードが呼び出されるのに十分な長さで、スクロールを停止するとアプリがクラッシュします。テキストをうまくフリックできます。着信パケットを処理する必要があるときだけですが、まだスクロールしているとクラッシュします。さらに、私がスクロールしている間、他には何も更新されません。受信したデータによって更新されるはずのすべてのラベルは同じままです。
私の考え
これは、アプリがスクロールと受信データの操作の両方を同時に処理できないかのようです。これは、メモリ管理に問題があるのか、スクロール機能を上書きする必要があるのか、それとも完全に上書きする必要があるのかわかりません。どんな助けや考えも大歓迎です。
解決
trumpetlicksが言ったように、これを行うには、ネットワークタスクにマルチスレッドを実装する必要がありました。次のようにしました。
初期化中:
NSOperationQueue *networkQueue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(initNetworkCommunication) object:nil];
[networkQueue addOperation:operation];
[operation release];
initNetworkCommunicationで、CFSocketpairとストリームを初期化した後:
[[NSRunLoop currentRunLoop] run]; //necessary to handle stream events