Ios 从异步回调更新UI时出现的问题

Ios 从异步回调更新UI时出现的问题,ios,objective-c,multithreading,Ios,Objective C,Multithreading,我有以下代码: @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)view

我有以下代码:

@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方法不会执行(我的意思是它会被执行,但UI不会更新)

我尝试了所有的方法来让它工作(包括通过GCD将[self hideLoadingScreen]分派到主线程,并执行SelectorOnMainThread/使一个u block BOOL变量在主线程上加载和休眠,直到该变量被更改,等等)。我还调用了ViewDidAspect方法上的hideLoadingView方法,它可以工作,但我希望在执行回调时隐藏它。不幸的是,我无法通过在stackoverflow上搜索找到解决方案,也无法在google上搜索(我必须说我尝试了我找到的所有解决方案)

L.E.我按照Rob Napier的建议记录了self.loadingView

新代码:

-(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太阳波报告[4566:282042]异步之前:
2016-01-08 16:22:25.973 sunwaves.报道[4566:282042]之前的hideLoadingScreen:
2016-01-08 16:22:25.974太阳波报道[4566:282042]hideLoadingScreen之后:
2016-01-08 16:22:25.974 sunwaves.报告[4566:282042]在以下时间后异步:

大多数UIKit调用必须在主队列上进行。您应该使用
dispatch\u async(dispatch\u get\u main\u queue(),…
来执行此操作

这至少包括对
reloadData
的调用

您对
self.data
的赋值也可能不是线程安全的(除非您在setter中做了一些特殊的操作),因此这些赋值必须在主队列中

当然还有您对
hideLoadingScreen
的调用

我假设这些块中的大多数都是在主队列之外执行的,因此这意味着在多个地方放入
dispatch\u 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];
            });
        }
    }];
}

self.data被分配,reloadData调用正在工作,但是视图不会隐藏。我知道self.data分配和reloadData都应该在主线程上被调用,但是hideLoadingScreen方法仍然没有更新UI。我尝试使用dispatch\u async作为您的答案,但没有成功。hideLoadingScreen方法是正确的nd做了预期的事情(我试着在ViewDidAspect方法上运行它)。谢谢,我很感激!添加日志记录。确保(a)
hideLoadingScreen
实际运行,(b)
self.loadingView
为非零。请注意,将值设置为hidden并同时将帧设置为零是很奇怪的。隐藏它应该足够了。再次感谢!我根据您的建议修改了我的问题。正如您所看到的,方法和回调引用了不同的UIView。知道为什么吗?哦,我错了。他们引用的是ame UIView(我把CALayer和UIView弄错了)。但是UI仍然没有更新。如果视图在此代码之后没有隐藏,则
self.loadingView
可能指向的内容与您认为的不同。例如,您可能已向superview添加了多个加载视图,因此
self.loadingView
仅引用其中一个。这尤其是一个非常复杂的问题我错了。
- (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];
            });
        }
    }];
}