-1

NSTimer在 Objective-C 中使用定期(1 分钟间隔)运行后台进程,该进程检查任何未保存的数据并通过 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

你的错误是这个电话:sendSynchronousRequest。简而言之就是这样。几乎没有任何理由同步发送 Web 请求 - 现在您知道为什么不应该这样做了。是同步的!这意味着它会在我们等待时阻塞线程——如果等待时间很长,就会有很长的阻塞。这是主线程,所以我们阻塞了用户界面,定时器,一切。

只需切换到异步请求并正确使用委托回调,一切都会好起来的。

于 2012-11-27T01:46:48.413 回答
2

计时器在主线程上触发。如果 syncExtSys: 方法没有及时完成,它将挂起主线程。

您的情况是您想做一些可能需要一段时间的事情,但您希望结果显示在主线程的 UI 中。处理此问题的一些好方法是使用 Grand Central Dispatch 执行以下操作之一:

  1. 使用计时器调度源在后台队列上进行处理,然后调度结果以显示在主队列上。
  2. 坚持使用 NSTimer,但将 syncExtSys: 中可能需要一段时间的任何内容分派到后台队列,然后在完成时将结果分派回主队列。
  3. 使用 syncExtSys: 中的所有非阻塞调用及其调用的所有内容。
于 2012-11-27T00:39:40.613 回答