On the change of one view to another i want to load uitableview data after the viewdidappear of the new view occurs because if i load them in viewdidload it takes too much time to update the interface and the reason is the data loading. I want the interface to be loaded first so the user will be presented with the new interface and a "Loading..." label. Then data loading will occur and lastly the uitableview will appear.
Any help appreciated.
Load your data in the background as follows. Fill in the details with your own code to update your UI as you like and track status of the data being loaded. You can also look into other methods of executing background ops (look at the Concurrency Programming Guide) for more options and control.
- (void)viewDidLoad
{
[self performSelectorInBackground:#selector(loadData) withObject:nil];
}
- (void)loadData
{
#autoreleasepool {
// load the data
[self performSelectorOnMainThread:#selector(didLoadData) withObject:nil waitUntilDone:NO];
}
}
- (void)didLoadData
{
}
Related
I have subclassed a CollectionView and using it using to display a collection of images in different categories. For example: Most Popular, Most Viewed. I access each category/page through a TabbarController.
The classes I have are:
Main class - MediaList - Base class for fetching and displaying media in a collection view depending on what type of media is requested.
SubClasses - MostPopular and MostViewed are both very light classes that inherit from the main class.
The problem is that when I move from MostPopular to MostViewed, the collection view initially displays the last category of pictures and then refreshes to the new...As a result you see a flicking effect.
Sample code from MediaList
- (void)viewDidLoad
{
[super viewDidLoad];
self.mediaCollection.dataSource = self;
self.mediaCollection.delegate = self;
[self getMedia];
}
(void) getMedia
{
NSLog(#"///////////////////////// GETTING MEDIA /////////////////////////");
XMLGenerator * sharedXmlGen = [XMLGenerator sharedXmlGenerator];
GlobalVars * sharedGlobalVars = [GlobalVars sharedGlobalVars];
sharedXmlGen.assetFlag = _contentFilter;
NSLog(#"The filter is: %#", _contentFilter);
[sharedXmlGen getPhotoVideoWithCallBackFunction:^{
[_mediaCollection performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}];
}
Sample code from SubClass (MostPopular):
- (void)viewDidLoad
{
[super setContentFilter:FILTER_POPULAR]; //Set the filter for the type of content
[super viewDidLoad];
// Do any additional setup after loading the view.
}
Two clarifications:
I should add that I am trying to re-use as much code as possible without having to create new views on the storyboard or controllers.
Because the media returned is very dynamic and can be updated regularly, I have had to reload my data (using getMedia) on viewDidAppear. This now means each selection of a particular page will result in the flickering when the new view is loaded...
Updates
- After further investigation it looks like this has nothing to do with subclassing the uicollectionview. The issue instead is just reloading data into the uicollectionview. To be sure, I just clicked on one of the two subclassed views. I also added a reload method to the viewdidAppear method just to see the issue get even worse. It's also much easier to see that the issue is that last set of images in the collection view initially displays the last category of pictures before the new one refreshes. Then once the collection is refreshed I get the flicker.
*Updates Oct 4 *
Starting to think my best solution is to display a waiting indicator and block the page while loading. I did try setting the uicollectionview to nil, and believe that will solve the problem as well, but not sure it will be straightforward to reset.
Although it may not be immediately apparent in the code above the root cause was actually the getMedia call. All of the subclassing etc. works perfectly fine.
Specifically having the reload method in the getMedia call and was creating the issue.
[_mediaCollection performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
Hi I have a uiviewcontroller that adds 4 childviews after receiving data from a webservice. I add an observer to the uiviewcontroller that watches when the data is completely loaded from the webservice. Once it is, the uiviewcontroler adds 4 childviews.
however my problem is it doesn't do this unless i switch to another tab view than go back to that tab again.
Is there a way to reload this page? I used [uiviewcontroller.view setNeedsDisplay] under the function that responds to the notification from the observer but the view doesn't refresh.
thanks for your guys' help :)
here is my observer function:
-(void)projectListFromServer:(NSNotification *) response
{
NSLog(#"%#",response);
for (int i = 0; i < 4; i++)
{
childview2 = [self.storyboard instantiateViewControllerWithIdentifier:(#"slider")];
childview2.image = #"wicked";
childview2.couponID = #"cool";
NSLog(#"%#", self.childview2.couponID);
[self addChildViewController:childview2];
}
[self.childview.view setNeedsDisplay];
}
You are calling addChildViewController, but then it looks like you aren't actually adding childview2's view hierarchy to this containing view controller's view hierarchy.
You'll need to do something like this, adjusted of course depending on where in your current hierarchy you actually want these new views to be inserted:
[self addChildViewController:self.childview2]; // assuming childview2 is a #property
[self.view addSubview:self.childview2.view]; // adjust based on your actual hierarchy
[self.childview2 didMoveToParentViewController:self];
BTW, you should avoid giving view controllers names like childview2. Views and view controllers are two completely different things.
Similar to this question: Adding subview, gets delayed?
But I don't think you can pushViewController in a separate thread so is this really impossible?
Here is what I'm trying to do:
I have a TableView and when a cell is pressed, I want to call
[self.view addSubview:LoadingView]
to display an overlay with a spinner. Then I call
self.navigationController.navigationBar.hidden = NO;
[self.navigationController pushViewController:newGameViewController animated:YES];
However, the subview only displays for a split second (~1-4 seconds after the cell selection occurs while it waits for the new viewcontroller to initialize).
Is there any way to get some sort of loading indicator to occur at the instant the cell is selected?
Okay. What about this. In your didSelectRowAtIndexPath start your spinner (via addSubview ...) and start loading your stuff from the server. If that's finished remove the spinner an push your new view controller onto the stack. Make sure the user can't touch any other cell during that time. By the way. From a users perspective I'd find it mor intuitive if the new controller is loaded immediately and displays some waiting message.
Or the other way around: The newGameViewController displays the spinner and starts loading the data from the server in a background thread. When the data is complete, remove the spinner and display the data. That way the user could even go back if she doesn't want to wait.
You do not need to add code before pushing newGameViewController.
Inside viewDidLoad of newGameViewController, write the code of displaying spinner. To get the updated UI, just insert a delay before calling a web API.
inside GameViewController.m
-(void) viewDidLoad
{
[self.view addSubview:LoadingView];
[self performSelector:#selector(callWebAPI) afterDelay:0.1];
}
-(void) callWebAPI
{
//Handle network activity here..
}
I'm using a UITableView control to show some data that can be edited by the user. To edit the details the user taps on an edit button which pushes a new view onto the stack. The user edits the data, taps a save button and the data is saved to a plist and the view popped off the stack. Even though the plist has been updated the UITableView still shows the old data. This can be corrected by adding a call to reloadData in the viewWillAppear method. However when the view is first loaded the data is displayed correctly, by adding the reload statement does this mean a double bind? If so, how can this be avoided?
I found the following code (here) which forces a refresh without explicitly calling reloadData:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
int orientation = [[UIDevice currentDevice] orientation];
if(orientation != UIDeviceOrientationUnknown)
[self willRotateToInterfaceOrientation:orientation duration:0];
}
Can anyone explain how/why this works?
The trick from your link is a dirty hack. Not only does it reload the data, but also forces the table to redraw. It tells your app that the device is getting a new orientation, so your table gets redrawn, along with other UI elements.
The standard way of refreshing a single row or a specific set of rows in your UITableView is calling its reloadRowsAtIndexPaths:withRowAnimation: method: doing so calls through to your data source to get data for only the row(s) that have been updated, preventing the full reload.
Do this:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//remove all objects from yourTableViewDataSourceArray
[yourTableViewDataSourceArray removeAllObjects];
//add new records from plist
yourTableViewDataSourceArray = plist request of data here
//reload table now
[yourtableView reloadData];
}
I put a function in viewWillAppear in my view controller so that it runs every time the view is loaded:
- (void)viewWillAppear:(BOOL)animated
{
[self initBasicSettings];
}
However, the function initBasicSettings is run every time a modal alert box (UIAlertView) is closed as well, which I do not want.
How do I make a function run when a view loads but not when an alert box closes? If these two events cannot be made disparate, I feel that it is not orthogonal design.
Assuming this is not a joke question. This method stub is inserted in new UIViewController subclasses by default.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
These images will clear your concept of viewWillAppear & viewWillDisappear works even when view is added to view hierarchy or removed from view hierarchy.
Image for view - when added to view hierarchy.
Image for view - when removed from view hierarchy.