質問

I'm creating an app that loads an sniffing-based database from one site, and all of this is done by "onlineSetup" method.

Since this method could be stuck for a while, I would like to set a statusText as "Connecting" so the user knows he has to wait. The problem is: the 'setTitle' is ignored until the method onlineSetup returns, even if the onlineSetup method is called after.

- (void)modeSwitchChanged:(id)sender
{
if (self.modeSwitch.isOn)
{
    [self setStatusText:@"Buscando dados: YokaiAnimes" withColor:[UIColor blackColor]];
    if ([self.db onlineSetup]) [self setStatusText:[NSString stringWithFormat:@"Animes encontrados: %d",self.db.animes.count] withColor:[UIColor greenColor]];
    else
    {
        [self.db offlineSetup];
        [self setStatusText:@"Falha: internte desconectada." withColor:[UIColor grayColor]];
        [self.modeSwitch setOn:false animated:true];
    }
}
else
{
    [self.mainTableView setBackgroundColor:[UIColor whiteColor]];
    [self setStatusText:@"Buscando dados: Memória Interna" withColor:[UIColor blackColor]];
    [self.db offlineSetup];
    [self setStatusText:[NSString stringWithFormat:@"Animes encontrados: %d",self.db.animes.count] withColor:[UIColor redColor]];
}
[self.mainTableView reloadData];
}

- (void)setStatusText:(NSString*)t withColor:(UIColor*)c
{
[self.statusLabel setTitle:t];
[self.statusLabel setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:c,NSForegroundColorAttributeName, nil] forState:UIControlStateNormal];
}
役に立ちましたか?

解決

Nothing happens in the interface until after all your code finishes running. That's how iOS works. Thus if you want your change in the interface to happen now, you need to get off the main thread for a moment to let the runloop finish cycling before you proceed.

- (void)modeSwitchChanged:(id)sender {
    if (self.modeSwitch.isOn) {
        [self setStatusText:@"Buscando dados: YokaiAnimes" withColor:[UIColor blackColor]];
        dispatch_async(dispatch_get_main_queue(), ^{
             // call onlineSetup here
        });
     // ...

Indeed, if onlineSetup is truly time-consuming, you should to it on a background thread (not dispatch_get_main_queue()), because if you hog the main thread for too long, you will be punished with instant death (well, your app will, anyway). But then of course ultimately you must get back on the main thread to make any further changes to the interface. This is why GCD is so great; it makes this kind of thread-switching easy and safe.

In fact, if you are doing networking, you should definitely be using asynchronous networking. The ability to do this is built right into iOS; if you are deliberately doing synchronous networking, stop right now and fix that. You get a callback at the end and you can get back on the main thread at that point.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top