2016-01-08 3 views
0

У меня есть следующий код:Проблем по обновлению пользовательского интерфейса от асинхронного обратного вызова

@property (weak, nonatomic) IBOutlet UIView *loadingView; 

-(void) hideLoadingScreen{ 
    self.loadingViewRect = self.loadingView.frame; 
    [self.loadingView setHidden:YES]; 
    [self.loadingView setFrame:CGRectMake(0,0,0,0)]; 
} 
- (void)viewDidAppear:(BOOL)animated{ 
    [self.apiClient checkLoggedInWithCallback:^(int status){ 
     if(status == ONLINE_LOGGED_IN){ 
      [self.dbAPI isPullSynchronized:^(BOOL isPullSynced){ 
       if(isPullSynced){ 
        self.data = [self.dbAPI getTodayVisits]; 
        [[self tableView] reloadData]; 
        [self hideLoadingScreen]; 
       } else { 
        [self.apiClient getTodayVisits:^(NSArray* visits){ 
         [self.dbAPI insertTodayVisits:visits withCallback:^(int status){ 
          self.data = [self.dbAPI getTodayVisits]; 
          [[self tableView] reloadData]; 
         }]; 
        }]; 
       } 
      }]; 
     } else if(status == ONLINE_NOT_LOGGED_IN || status == ONLINE_INVALID_TOKEN || status == OFFLINE_NOT_LOGGED_IN) { 
      //Redirect to login 
     } else { 
      //Get from Local DB 
      self.data = [self.dbAPI getTodayVisits]; 
      [[self tableView] reloadData]; 
     } 
    }]; 
} 

Метод hideLoadingScreen не будет выполнять (я имею в виду она будет выполнена, но интерфейс не обновляется).

Я пробовал все, чтобы заставить его работать (в том числе отправить [self hideLoadingScreen] в основной поток через GCD и выполнитьSelectorOnMainThread/сделать переменную BOOL __block isLoading и спать в основном потоке до тех пор, пока эта переменная не была изменена и т. Д.). Я также вызвал метод hideLoadingView метода viewDidAppear, и он работает, но я хочу, чтобы он скрывался при выполнении обратного вызова. К сожалению, я не смог найти решение, выполнив поиск в stackoverflow, ни в google (я должен сказать, что я пробовал все найденные решения).

L.E. Я вошел self.loadingView, как Rob Napier предложил

Новый код:

-(void) hideLoadingScreen{ 
    self.loadingViewRect = self.loadingView.frame; 
    NSLog(@"hideLoadingScreen before: %@",self.loadingView); 
    [self.loadingView setHidden:YES]; 
    [self.loadingView setFrame:CGRectMake(0,0,0,0)]; 
    NSLog(@"hideLoadingScreen after: %@",self.loadingView); 
} 

- (void)viewDidAppear:(BOOL)animated{ 
    NSLog(@"%@",self.loadingView); 
    [self.apiClient checkLoggedInWithCallback:^(int status){ 
     if(status == ONLINE_LOGGED_IN){ 
      [self.dbAPI isPullSynchronized:^(BOOL isPullSynced){ 
       if(isPullSynced){ 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         self.data = [self.dbAPI getTodayVisits]; 
         [[self tableView] reloadData]; 
         NSLog(@"async before: %@",self.loadingView); 
         [self hideLoadingScreen]; 
         NSLog(@"async after: %@",self.loadingView); 
        }); 
       } else { 
        [self.apiClient getTodayVisits:^(NSArray* visits){ 
         [self.dbAPI insertTodayVisits:visits withCallback:^(int status){ 
          self.data = [self.dbAPI getTodayVisits]; 
          [[self tableView] reloadData]; 
         }]; 
        }]; 
       } 
      }]; 
     } else if(status == ONLINE_NOT_LOGGED_IN || status == ONLINE_INVALID_TOKEN || status == OFFLINE_NOT_LOGGED_IN) { 
      //Redirect to login 
     } else { 
      //Get from Local DB 
      self.data = [self.dbAPI getTodayVisits]; 
      [[self tableView] reloadData]; 
     } 
    }]; 
} 

Журналы:

2016-01-08 16:22:25.973 sunwaves.reporting[4566:282042] async before: <UIView: 0x7fa681e745d0; frame = (0 0; 1024 650); autoresize = RM+H+BM; layer = <CALayer: 0x7fa681e291c0>> 
2016-01-08 16:22:25.973 sunwaves.reporting[4566:282042] hideLoadingScreen before: <UIView: 0x7fa681e745d0; frame = (0 0; 1024 650); autoresize = RM+H+BM; layer = <CALayer: 0x7fa681e291c0>> 
2016-01-08 16:22:25.974 sunwaves.reporting[4566:282042] hideLoadingScreen after: <UIView: 0x7fa681e745d0; frame = (0 0; 0 0); hidden = YES; autoresize = RM+H+BM; layer = <CALayer: 0x7fa681e291c0>> 
2016-01-08 16:22:25.974 sunwaves.reporting[4566:282042] async after: <UIView: 0x7fa681e745d0; frame = (0 0; 0 0); hidden = YES; autoresize = RM+H+BM; layer = <CALayer: 0x7fa681e291c0>> 

ответ

2

Большинство UIKit звонков должно быть сделано на главной очереди. Для этого вы должны использовать dispatch_async(dispatch_get_main_queue(),....

Это включает в себя ваши звонки на reloadData как минимум.

Вы назначаете self.data, также, вероятно, не потокобезопасны (если только вы не сделали что-то особенное в сеттере). Поэтому они должны находиться в главной очереди.

И, конечно, ваши звонки на номер hideLoadingScreen.

Я предполагаю, что большинство из этих блоков выполняются с главной очереди, так что это означает, что в нескольких местах помещается dispatch_async.

- (void)viewDidAppear:(BOOL)animated{ 
    [self.apiClient checkLoggedInWithCallback:^(int status){ 
     if(status == ONLINE_LOGGED_IN){ 
      [self.dbAPI isPullSynchronized:^(BOOL isPullSynced){ 
       if(isPullSynced){ 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         self.data = [self.dbAPI getTodayVisits]; 
         [[self tableView] reloadData]; 
         [self hideLoadingScreen]; 
        }); 
       } else { 
        [self.apiClient getTodayVisits:^(NSArray* visits){ 
         [self.dbAPI insertTodayVisits:visits withCallback:^(int status){ 
          dispatch_async(dispatch_get_main_queue(), ^{ 
           self.data = [self.dbAPI getTodayVisits]; 
           [[self tableView] reloadData]; 
          }); 
         }]; 
        }]; 
       } 
      }]; 
     } else if(status == ONLINE_NOT_LOGGED_IN || status == ONLINE_INVALID_TOKEN || status == OFFLINE_NOT_LOGGED_IN) { 
      //Redirect to login 
     } else { 
      //Get from Local DB 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       self.data = [self.dbAPI getTodayVisits]; 
       [[self tableView] reloadData]; 
      }); 
     } 
    }]; 
} 
+0

self.data присваивается, а вызов reloadData работает, но представление не скрывает. Я понимаю, что как назначение self.data, так и reloadData следует вызывать в основном потоке, но метод hideLoadingScreen по-прежнему не обновляет пользовательский интерфейс. Я попытался использовать dispatch_async, как в вашем ответе, без успеха. Метод hideLoadingScreen корректен и делает то, что ожидается (я попробовал запустить его по методу viewDidAppear). Спасибо, хотя, я ценю это! – bandrei2408

+0

Добавить регистрацию. Убедитесь, что (a) 'hideLoadingScreen' фактически запущен, (b)' self.loadingView' не равен нулю. Обратите внимание, что установка значения для скрытия, а также установка кадра в ноль является нечетной. Скрывать его должно быть достаточно. –

+0

Еще раз спасибо! Я изменил свой вопрос с вашими предложениями. Как вы можете видеть, метод и обратный вызов относятся к разным UIView. Любая идея почему? – bandrei2408

Смежные вопросы