Hi there
I ran into some confusion related to this; i would like to perform some actions only once the view is appeared, probably showing an activity indicator while the data is being collected.
I have written my code in viewWillAppear, but it seems to be firing before the view appears on the screen.
I have double checked this with some NSLog statements, and i added a sleep of 2 seconds in viewWillAppear, the NSLog statements get fired, and the view appears only after 2 seconds delay - i was expected, the 2 second delay is executed once the view comes onto the screen?
Am i doing something wrong?
I even tried viewDidAppear, same thing. Any suggestions?
Thanks
edit: I would like to give a clear scenario of what i am doing
1. i have a parent view, which has a scroll view - and a subview
2. In the parent view, i create multiple instances of the subview and add them to the scrollview, creating scrollable views, which work.
3. Each view is passed an argument and depending on the argument the view contents change - works as expected.
4. I would like to show the subview and once its on the screen, do some internet opearations while i show an activity indicator, for this i need to use viewDidApper.
5. I am manually firing the subview's viewDidAppear from the parent view, once i have created its instance
The problem here is, the view is appearing only once all the operations are complete.
How can i sort this?
viewWillAppear is supposed to fire BEFORE the view appears, hence the word Will in the name. You might be interested in viewDidAppear.
I guess i figured it out -
Rather than performing operations on viewDidAppear, i used performSelector, something like this
-(void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self performSelector:#selector(loadXML:) withObject: self afterDelay:0];
}
Thanks guys!
Related
I get used to put either of viewWillAppear and viewDidLoad, it's OK until know. However I'm thinking there should be some rules that guide when to put into viewWillAppear and when to put into viewDidLoad?
Simple rule I use is this. viewDidLoad is when the view's resources are loaded. The view is not drawn onscreen yet. So calculations and code dealing with the geometry and visuals of the view should not be put here. They should be in the viewWillAppear or viewDidAppear method.
Also viewWillAppear can be called multiple times
When a popover/modal view is displayed and remove
When an alert view/actionsheet/uiactivityController's view is displayed and removed.
For these reason, viewWillAppear should not contain codes that takes longer to finish. (at least the code running on the main thread). Neither should codes that only needs to be run once per view display.
There are more I am sure but these are simple to remember and I hope it helps.
viewDidLoad: Alerts you that a view has finished loading
viewWillAppear: Runs just before the view loads
viewDidLoad is things you have to do once. viewWillAppear gets called every time the view appears. You should do things that you only have to do once in viewDidLoad - like setting your UILabel texts. However, you may want to modify a specific part of the view every time the user gets to view it, e.g. the iPod application scrolls the lyrics back to the top every time you go to the "Now Playing" view.
However, when you are loading things from a server, you also have to think about latency. If you pack all of your network communication into viewDidLoad or viewWillAppear, they will be executed before the user gets to see the view - possibly resulting a short freeze of your app. It may be good idea to first show the user an unpopulated view with an activity indicator of some sort. When you are done with your networking, which may take a second or two (or may even fail - who knows?), you can populate the view with your data. Good examples on how this could be done can be seen in various twitter clients. For example, when you view the author detail page in Twitterrific, the view only says "Loading..." until the network queries have completed.
I've been working for a while now on switching UIViews, and am trying a basic UIView switch, without using UINavigationController. I've looked into UINavigationControllers, but I have been wrestling with the below for so long that I want to explore it fully.
My project organisation is:
MainViewController.h/.m -> viewDidLoad: This method runs a NSTimer to update self.view with a few bits and bobs.
ConfigView.h/.m: -> viewDidLoad: nothing - just an idle view.
MainViewController.xib -> Main window NIB
ConfigView.xib -> ConfigView NIB
I have the following method in MainViewController.m execute on a UIButton press event:
- (IBAction)switchToConfigView:(id)sender {
if(self.configViewController == nil) {
ConfigView *cv = [[ConfigView alloc] initWithNibName:#"ConfigView" bundle:nil];
self.configViewController = cv;
[cv release];
}
[self.view addSubview:configViewController.view];
}
Now, when I switch to the ConfigView, the view is indeed displayed, but it appears that viewDidLoad: from MainViewController still executes, causing both views to effectively be merged. From the code, I can see that this is obviously the case, as the actual view switch itself is performed within the MainViewController context, and as you can see, simply a subview.
My question is, how do I neatly tuck away/pause all goings-on within MainViewController when switching the view by just adding another subview to it? My guess is that it's not possible, or rather it's a lot of leg work where some other methodology would be better applied. I suspect I need to implement the actual switch from the ConfigView.h/.m but I could be wrong.
Any light you can shed on the above would be grand.
thanks
swisscheese.
My suggestion is:
1) have a base, empty view;
2) add a subview to it; this would be your actual first view;
3) when you want to switch, remove the first subview from the base view and add the second one as a subview;
4) when you want to switch back, remove the second one and add the first one as a subview to the base view;
you can easily handle as many view as you like. it works.
alternatively, you can hide the view instead of removing it.
Believe me adding a whole new sub-view on another view is really a massive task and later on when the project becomes big it becomes a painful task to switch views.
This is my own personal experience as I did this big mistake in one of my previous project.
In all cases navigation control is the best choice for switching views rather than adding sub-views.
Please tell me that what difficulties are you facing in Navigation control and I can help about this.
Thanks,
If the NSTimer you've set up in MainViewController's viewDidLoad method is adding subview's to mainViewController's view with the addSubview method, those views will be placed on top of all other subviews, i.e. on top of the config view. So, you might try either invalidating the timer when presenting the config view.
You should really just use a UINavigationController, or present the config view controller with presentModalViewControllerAnimated. Why don't you want to?
I have viewBased Application, i have 3 view controller in that.
When I want to go back to first view from second view, I want that view to be reloaded from start.
Code I use to dismiss the present view is:
//Back Button Code:
[self dismissModalViewControllerAnimated:YES];
//Code I use to go to new view is:
[self presentModalViewController:secondView animated:YES];
I am not getting what you trying to do...
put your logic inside viewWillAppear method... which gets called everytime view Loads..
When I want to go back to first view from second view, I want that view to be reloaded from start.
Wich one?
Well I think it should work since dismissing a modal dialog unloads it. What happens exactly that you don't want? You must have retained something you don't want to.
It's not clear if you want your first view to restart, or your second view to restart.
Answer for both cases:
If you want view 1 to restart, move the code you need re-executed into viewWillAppear()
If you want view 2 to restart, it's been released from memory so going back to it will call viewDidLoad() and restart it anyway.
Hope that helps....
I am a working UINavigationController pushing two different UITableViews on and off the stack. All of my functionality is working correctly except scrolling. When either table is scrolled above the top row, or below the bottom row, it stays there exposing the margin above/below the table. I am looking for the table to "bounce" back so that only the table is visible and not the white space area beyond - just like any other iPhone app.
One of my UITableViews is being loaded by NIB and the other is being created programatically - both of which have the exact same result. I have tried all the bounce and scrolling settings in the Nib, but nothing seems to work.
Can someone tell me what I am doing wrong? Please let me know if I can be more specific in detailing my problem.
Thanks,
-Scott
I wanted to add a bit more information since I am still unable to figure out this problem. I should point out that the app I am trying to add this NavigationController to is NOT the main view. I have a SettingsViewController that uses a Nib to get loaded. Within that controller, I am wanting to create a new navigation based set of views. So From inside my SettingsViewController, if the user taps a button, I...
Within my button selector:
TextListViewController *controller = [[TextListViewController alloc] initWithStyle:UITableViewStylePlain];
controller.title = #"Test Table View";
navController = [[UINavigationController alloc] initWithRootViewController:controller];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:navController animated:YES];
[controller release];
The above code works perfectly in every way except scrolling. I am able to process all the delegate methods and push new controllers onto the stack. The ONLY issue I am having is that the root controller (and every other controller pushed) will not scroll correctly.
In every case, it allows me to scroll past the top and bottom of the table and does not snap back like it should. It also does not have a free-wheel feel to it when you flick scroll. Instead, it stops as soon as you remove your finger no matter how fast you scrolled. Very odd.
I have tried creating another project using the Navigation template - and of course it works fine - but the template assumes the NavigationController's view is attached all the time - which is not my case. I am creating all of this on the fly within a standard ViewController.
Thanks for your help Kevin, but I am still looking for some help here.
Thanks,
Well, I fixed the issue and it had nothing to do with how I was adding the UITableView to the UINavigationController or in how I was instantiating the view. It turns out it was completely unrelated to any of that.
I am using a tight while loop to process my game loop. I needed a way to process OS messages in the loop to keep touches and other events from being blocked. Here is what I was using in the middle of my loop:
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, TRUE) == kCFRunLoopRunHandledSource);
Up until this scrolling problem, I had no problems with this implementation at all. For whatever reason, this is breaking the scrolling functionality with UITableView.
I changed my game loop so the above code is not needed and everything started working.
Thanks...
Your UITableView is a UIScrollView, whose property bounces is the key. Here's the reference. By default it is YES, though. Did you check this one?
Your question and comments seem to suggest that you are attaching a UITableView to your UINavigationController in some way other than by pushing a UITableViewController. If you're not doing it that way, you really should.
In general, if you can push a child view controller onto a UINavigationController, then you can also use the child view controller by itself just to test it out. Try making your UITableViewController's view the root view of your window, and see if that does what you expect. That way you can isolate the problem to either the table view part or the navigation part.
I've been having the same issue as you which as you state above was related to the way you were calling the runloop:
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, TRUE) == kCFRunLoopRunHandledSource);
Seems like DefaultMode is the wrong thing to be waiting on, I changed my code to wait on UITrackingRunLoopMode and the TableView worked correctly. In my case I used:
[[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate distantFuture]];
And everything worked correctly.
The app in question has a MainView->ModalView pair. The ModalView is shown via UIModalTransitionStyleFlipHorizontal. In case of didReceiveMemoryWarning, MainView is dumped (since it is not visible) and the app stays "alive" but when you flip back there is a (very) short period of time when the screen is blank (since the modal dialog is returning to a now-deallocated view). When the animation transition is over, MainView is regenerated and all is ok.
I just would like to somehow regenerate MainView before returning from ModalView (in case of a memory warning).
Is this a good idea? Am I doing something wrong as far as the warning is concerned?
Thanks
You might want to try to reload your MainView, before you start the flip, so that there is no blank screen to wait for. That does mean that your flip will be delayed, but maybe that is better?
If you want to reload your MainView before you head to it, try to access MainView like this
if (MainView)
....
if the MainView is a view or like this
if (MainView.view)
.....
if the MainView is a view controller. What the access of the view does is to force a reload of that view from the NIB, or loadView.
You can also choose to ignore the memory warning by commenting out the section in DidReceiveMemoryWarning - do at your own risk though :)