View displaying on top of loading icon due to async call - ios

I was doing everything in a single thread and have just started moving to asynchronous calls so I'm a bit confused.
What I would like is for the view to load, either with an empty table or with no table at all. The MBProgressHUD should show while the async call gets the data. Then when the data is found the HUD goes away and the table refreshes.
What I have now is everything works except that the HUD is displayed underneath the empty table. Here is the most relevant code.
- (void)awakeFromNib
{
[super awakeFromNib];
[MBProgressHUD showHUDAddedTo:self.tableView animated:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.dataController = [[StudyController alloc] initWithCredentials:email password:password];
dispatch_sync(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.tableView animated:YES];
[self.tableView reloadData];
});
});
}
Basically what is happening, I think, is all my code that was rendering the table correctly runs once while the async call is running, and shows an empty table on top of the HUD, and then again after the call when I tell it to reloadData. How do I get it to not run that first time?
Thanks.

It's hard to gauge without seeing your table view delegate/datasource methods, but your intuition makes sense. In this case, I can see two options:
Add some logic to your delegate/datasource methods to properly show your loading view if the table is empty.
Rather than add the loading view to the table view, add the loading view to the table view's superview. That way, you can ensure that the loading view is always on top of the table view.
I usually opt for the second method, because I prefer to focus my datasource and delegate methods on only the table view.
Hope this helps!

Related

The best way to update multiple cells in a collection view?

I have a collection view with a flow layout that shows multiple cells. Every cell has some async loading happening before it displays an image and some text. What is the best way to update these cells in succession?
I am doing something like this that works but I'm noticing my collection view gets frozen for a second or so if multiple cells get finished at the same time.
dispatch_async(dispatch_get_main_queue(), ^{
[collectionView reloadItemsAtIndexPaths:#[indexPath]];
});
It would be nice to add some more of your code, But it is actually better to do this kinda stuff with performBatchUpdates instead of doing it in main thread.
- (void)performBatchUpdates:(void (^)(void))updates
completion:(void (^)(BOOL finished))completion;
Here is the documentation

How do display a refreshed view without touching it first?

Well, the title already says it all. I have a view (a table view in my special case embedded in a non-table view controller) and at some time in code I want to update cells and display the update. The first part works like a charm but the changes won't displayed after the reloadData() - and even when I call setNeedsDisplay() afterwards.
When the controller has to update something the tableview will be also re-drawn and the changes are visible. As soon as I touch the tableview cell the changes are also visible. Without touch the update just isn't displayed.
I've come across this issue and using GCD should solve it
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});

Refresh tableviewcontroller in ios

I am trying to refresh the table view controller when certain task is performed inside a block.I have checked questions on stackoverflow but they deal with refresh option but i want it to just reload view and go to viewDidLoad and ViewWillAppear.This was the suggestions.
[self.tableView reloadData];
but it doesn't seem to work.Any ideas?
You can not reload tableview or update any view inside a block. If you want to update or refresh your table then you will have create a main threaded block and write your code for table refresh on the main thread.
So, try this code:
dispatch_async(dispatch_get_main_queue(), ^{
enter code here
});

UICollectionView Reloading Data

A question regarding reloading data in your UICollectionView.
When using reloadData it only does this once any scrolling has finished. Then there is a small pause where the collection view freezes and cannot be interacted with until the new data is loaded in. How can I get around this?
For example, I would have a view comprised of maybe 10/20/30 items, each with an image and label. I then update my dictionary with new images and strings and then reload the view to add these new items.
Many thanks.
EDIT:
On closer inspection, its not the reloading that causes the pause, its some other code, where I fetch some data. Why might this freeze my view though when i am not even reloading it to make changes to it?
I am fetching this data from -(void)scrollViewDidScroll:(UIScrollView *)scrollView
EDIT 2:
Ok here is some basic code
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self myMethodWithCompletionBlock:^(NSMutableDictionary *results, NSString *nextPageToken) {
//No code in completion block is ever called when the method is called in the dispatch block! Regardless of what it is.
}
});

Where to load my array?

- (void)viewWillAppear:(BOOL)animated
{
goals = [[NSArray alloc] init];
goals = [[self.operation valueForKeyPath:#"goal.goalNaam"] allObjects] ;
[self.tableView reloadData];
I'm loading my elements for my tableview in viewwillappear, as you can see in the code above. When the user adds something to the table (adding happens in a different view), it's added to Core Data and the array is loaded when the tableview is again appearing (after the dismissed "add-an-element-view"), now I want to delete something from the table. But the problem is that we're now staying in the same view (the tableview), so my array is not reloading (cause the viewwillappear is not executed). Anybody an idea how to solve this ?
You can call "[self viewWillAppear:YES];" after delete the data from Core data, So the datas are reloaded from the same view (Tableview)
You load your data in cellForRowAtIndexPath. This is called as cells come into view, and only cells in view (or almost in view) are loaded.
To force something to be reloaded, use reloadRowsAtIndexPaths or one of the other reload... methods.
Check out NSFetchedResultsControllerDelegate . You can set your VC as the fetch result delegate, and be notified when the data structure changes.

Resources