-1

私はNSTimerObjective-Cで使用して、バックグラウンドプロセスを定期的に(1分間隔で)実行しています。このプロセスは、保存されていないデータをチェックし、Webサービスを介してデータベースに送信します。このプロセスは、Webサーバーが再起動された特定のシナリオまで、メインアプリケーションのフローをブロックすることなく正常に実行されます。

Webサーバーが起動しているとき、バックグラウンドプロセスはサーバーに接続しようとしていて、サーバーが完全に起動して到達可能になるまでそこでハングアップしていました。ハングアップすると、メインアプリケーションのフローもブロックされ、画面全体がフリーズしました。Webサーバーが完全に起動すると、ハングアップしたプロセスが再開され、メインアプリケーションも動作を再開しました。

バックグラウンドプロセスがハングしたときにメインアプリケーションが断続的にフリーズした理由を教えてください。

次のコードはタイマーを開始します

- (void) startSync{
    syncTimer = [NSTimer scheduledTimerWithTimeInterval:60
                                         target:self
                                       selector:@selector(syncExtSys:)
                                       userInfo:nil
                                        repeats:YES];
}

次のメソッドは60秒ごとに呼び出され、saveAgendaToDbメソッド呼び出しはWebサービスを呼び出します。

- (void) syncExtSys:(NSTimer *) theTimer{
    UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:[NSBundle mainBundle]];
    AgendaItemViewController *agendaItemViewController = [storyboard instantiateViewControllerWithIdentifier:@"AgendaItemViewController"];
    RollCallViewController *rollCallViewController = [storyboard instantiateViewControllerWithIdentifier:@"RollCallViewController"];

    for(int i=0;i<agenda.count;i++){
        unsavedAgenda = [agenda objectAtIndex:i];
        if(unsavedAgenda !=nil && [unsavedAgenda.dirtyFlag isEqualToString:@"Y"] && [self checkNetworkStatus]){

            NSLog(@"agenda out of sync = %@ %@",unsavedAgenda.measureType,unsavedAgenda.measureNum);
            [agendaItemViewController saveAgendaToDb:[agendaItemViewController createDictForAgenda:unsavedAgenda]:unsavedAgenda];
        }
    }
    for(int i=0;i<_rollCall.count;i++){
        Member *member = [_rollCall objectAtIndex:i];

        if(member !=nil && [member.dirtyFlag isEqualToString:@"Y"] && [self checkNetworkStatus]){

            [rollCallViewController saveRollCall:[rollCallViewController createRollCall]];
            break;
        }
    }

    [self calcDirtyFlag];
}

Webサービスを呼び出すコード

-(void) saveAgendaToDb:(NSMutableDictionary*) agendaDictionary:(AgendaItem*) agenda{
    NSError *error;
    CommVotesAppDelegate *delegate = (CommVotesAppDelegate *)[[UIApplication sharedApplication] delegate];
    @try{

        NSString *postUrlString = [NSString stringWithFormat:@"%@%@:%@%@%@/%@",@"http://",delegate.prop.serverName,
                                   delegate.prop.port,delegate.prop.urlPattern,delegate.prop.saveAgendaMethod,delegate.prop.objectType];
        NSURL *postUrl = [NSURL URLWithString:postUrlString];
        NSMutableURLRequest *urlRequestPost = [[NSMutableURLRequest alloc] initWithURL:postUrl];
        NSData *postData = [NSJSONSerialization dataWithJSONObject:agendaDictionary options:0 error:&error];
        [urlRequestPost setHTTPMethod:@"POST"];
        [urlRequestPost setValue:@"text/plain" forHTTPHeaderField:@"Accept"];
        [urlRequestPost setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        [urlRequestPost setHTTPBody: postData];
        // NSLog(@"After calling webservices");
        NSData *returnData = [ NSURLConnection sendSynchronousRequest: urlRequestPost returningResponse: nil error: &error ];
        NSString *returnString = [[NSString alloc] initWithData:returnData encoding: NSUTF8StringEncoding];
        NSLog(@"Response after calling save agenda web service = %@",returnString);
       [delegate dirtyFlagCalc:returnString :[error localizedDescription]:agenda];
    }@catch(NSException *nserror){
      NSLog(@"Error while sending agenda through webservices = %@",nserror.debugDescription);
    }@finally {
        NSLog(@"Inside finally block of agenda saving ");
        [delegate saveDataToDisk];
    }
}
4

2 に答える 2

2

タイマーはメインスレッドで起動します。syncExtSys:メソッドがすぐに完了しない場合、メインスレッドがハングします。

あなたの状況は、潜在的に時間がかかるかもしれない何かをしたいが、結果をメインスレッドのUIに表示したいということです。これを処理するいくつかの良い方法は、GrandCentralDispatchで次のいずれかを実行することです。

  1. タイマーディスパッチソースを使用してバックグラウンドキューで処理を実行し、結果をディスパッチしてメインキューに表示します。
  2. NSTimerを使い続けますが、syncExtSys:で時間がかかる可能性のあるものはすべてバックグラウンドキューにディスパッチし、完了時に結果をメインキューにディスパッチします。
  3. syncExtSys:およびそれが呼び出すすべての非ブロッキング呼び出しを使用します。
于 2012-11-27T00:39:40.613 に答える
2

あなたの間違いはこの呼び出しです:sendSynchronousRequest。一言で言えばそれだけです。Web要求を同期的に送信する理由はほとんどありませ。これで、送信しない理由がわかりました。同期です!つまり、待機中はスレッドをブロックします。待機時間が長い場合は、ブロックが長くなります。これはメインスレッドなので、ユーザーインターフェイス、タイマー、すべてをブロックします。

非同期リクエストに切り替えて、デリゲートコールバックを適切に使用するだけで、すべてうまくいきます。

于 2012-11-27T01:46:48.413 に答える