3

バックグラウンド

私のアプリはネットワークストリームからデータを取り出し、画面上の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
4

2 に答える 2

0

ここから始める。

developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/…あなたは

また、ネットワーク設定と使用法コードを追加して、そこで何をしているかを全員が確認できるようにします。

于 2012-06-22T15:14:06.363 に答える
0

私はあなたを助けることができる3つのアイデアを提案することができます:

1)バックグラウンドスレッドからUI要素を呼び出さないでください。常にメインスレッドに移動するため、たとえば次のように使用します。

   dispatch_async(dispatch_get_main_queue(), ^{

         self.textview.text = .....

    });

2)スレッド間で何らかの同期を使用します(詳細は後で説明します)。

3)NSOperationはこのタスクには複雑すぎます。単に、NSURLSessionコールバックを使用し、完了時に、シリアル化する必要がある「中央」メソッドを呼び出します(2で述べたように))

すべてのネットワークコールバックで次のように仮定します。

...
    // create Session and request...
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                NSString * s = [[NSString alloc]initWithData:data encoding: NSUTF8StringEncoding];
                                                [self serializer:s];
                                            }
                                  ];
    [task resume];
...

4)次に、同期を試みましょう(そして、UIのメインスレッドに移動します。)

「init」/ViewDidLoadで作成します

self.queue = dispatch_queue_create("com.acme.myQueue", DISPATCH_QUEUE_CONCURRENT);

5)シリアライザー方式で使用します。

-(void) serializer:(NSString*)s
{
    dispatch_barrier_async(self.queue, ^{
        [self updateUI:s];
    });
}

6)UIの更新:

-(void) updateUI:(NSString*)s
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString * currText = self.textView.text;
        self.textView.text = [NSString stringWithFormat:@"%@\n%@", currText, s];

    });
}

ですから、私のコントローラーをすべて要約すると、次のようになります(詳細はあなたに任されています。)

@interface ViewController ()

@property dispatch_queue_t queue;
@property UITextView * textView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.queue = dispatch_queue_create("com.acme.myQueue", DISPATCH_QUEUE_CONCURRENT);

    [self startDownloadFromURL:@"https://www.apple.com"];
    [self startDownloadFromURL:@"https://www.google.com"];
}


-(void)startDownloadFromURL:(NSString*)urlString{

    NSURLSession * session;
    NSURLRequest * request;

    // create Session and request...
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                NSString * s = [[NSString alloc]initWithData:data encoding: NSUTF8StringEncoding];
                                                [self serializer:s];
                                            }
                                  ];
    [task resume];
}

-(void) serializer:(NSString*)s
{
    dispatch_barrier_async(self.queue, ^{
        [self updateUI:s];
    });
}


-(void) updateUI:(NSString*)s
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString * currText = self.textView.text;
        self.textView.text = [NSString stringWithFormat:@"%@\n%@", currText, s];

    });
}





@end
于 2017-08-19T20:47:16.700 に答える