问题
What I like: Wait until data download completes then open TableView
and show data
.
What I have: When prepareForSegue
is called the TableView
opens immediately without waiting for the data
download although I have a completionBlock
(which may not be implemented correctly I guess).
Note: When I go back and open the TableView
again I see the data
.
- (void)fetchEntries
{
void (^completionBlock) (NSArray *array, NSError *err) = ^(NSArray *array, NSError *err)
{
if (!err)
{
self.articlesArray = [NSArray array];
self.articlesArray = array;
}
};
[[Store sharedStore] fetchArticlesWithCompletion:completionBlock];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[self fetchEntries];
if ([[segue identifier] isEqualToString:@"ShowArticles"])
{
TableVC *tbc = segue.destinationViewController;
tbc.articlesArrayInTableVC = self.articlesArray;
}
}
Store.m
- (void)fetchArticlesWithCompletion:(void (^) (NSArray *channelObjectFromStore, NSError *errFromStore))blockFromStore
{
NSString *requestString = [API getLatestArticles];
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
Connection *connection = [[Connection alloc] initWithRequest:req];
[connection setCompletionBlockInConnection:blockFromStore];
[connection start];
}
回答1:
You should load your data before you perform a seque.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// show loading indicator
__weak typeof(self) weakSelf = self;
[[Store sharedStore] fetchArticlesWithCompletion:^(NSArray *array, NSError *err)
{
[weakSelf performSegueWithIdentifier:@"ShowArticles" sender:weakSelf];
// hide loading indicator
}];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// do whatever
}
Although in my opinion it is much nicer to immediately show the next view controller in response to a user interaction. Have you considered loading your data in the next view controller, instead of waiting for it before you actually want to transition?
回答2:
I still recommend Joris' answer more than this, but in theory, you could do something funky like:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
if ([identifier isEqualToString:@"segueIdentifier"] && !_didFinishExecutingBlock)
{
[self methodWithCompletionBlock:^{
_didFinishExecutingBlock = YES;
[self.navigationController performSegueWithIdentifier:identifier sender:self];
}];
return false;
}
else
return true;
}
回答3:
It's not going to wait since you are using a block and that is executed as soon as it's declaration is done, a solution would be to remove the block
- (void)fetchEntries
{
if (!err)
{
self.articlesArray = [NSArray array];
self.articlesArray = array;
}
[[Store sharedStore] fetchArticlesWithCompletion:completionBlock];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[self fetchEntries];
if ([[segue identifier] isEqualToString:@"ShowArticles"])
{
TableVC *tbc = segue.destinationViewController;
tbc.articlesArrayInTableVC = self.articlesArray;
}
}
来源:https://stackoverflow.com/questions/14506559/ios-prepareforsegue-doesnt-wait-for-the-completionblock-to-be-completed