i'm trying to remove a UIViewController from the superview after receiving a notification but it doesn't work.
in my appDelegate i do something like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application{
NSLog(#"applicationDidFinishLaunching");
[window addSubview:tabBar.view];
splash = [[SplashViewController alloc] init]; <-- this i want to remove
[window addSubview:splash.view];
[window makeKeyAndVisible]; }
in the SplashViewController i register the view to receive NSNotifications like this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fadeScreen:) name:#"CloseSplashScreen" object:nil];
the SplashViewController appears right after the Default.png and should fade smoothly after some data is parsed...
in my TableViewControler i want to send the notification in the viewWillAppear method but it doesn't work.
- (void)viewWillAppear:(BOOL)animated{
NSLog(#"viewWillAppear");
[[NSNotificationCenter defaultCenter] postNotificationName:#"CloseSplashScreen" object:self];}
the method gets called but the view is not removed from the superview. i tried to put the postNotification in - (void)viewDidLoad but the method doesn't get called...
any ideas why this is not working? thank you in advance
Since it looks like you are trying to implement some sort of splash screen, consider using a UINavigationController to present the splash. What you are doing is adding a view controllers view as a subview of UIWindow yet no one is managing your view controller. This is not how you should be doing things.
UIWindow has the method setRootViewController which should be in your appDelegate. That way you can push your Splash Controller, and after a certain interval push the first viewController of the app.
As a sidenote, I understand that some developers use splash screens as a means of reinforcing brand identity. That being said, consider Apples Human Interface Guidelines:
As much as possible, avoid displaying a splash screen or other startup
experience. It’s best when users can begin using your app immediately.
Related
Here is my project:
It only crashes in iOS8.
I have 5 view controllers:rootViewController,A,B,C and D.Every view controller has a button that present another view controller except D. Evert time presenting a view controller, the Manager singleton object will add the presented view controller into an array. The last view controller D, which has a dismiss button, will use the array to dismiss view controller,and here's the code:
while ([Manager sharedManager].viewCont.count) {
UIViewController *viewController = [[Manager sharedManager].viewCont lastObject];
[viewController dismissViewControllerAnimated:NO completion:nil];
[self removeViewCon];
}
But I meet a crash,which shows:
I use some manage object because I want to manage the view controllers in some case.
My question is why this crash occurs when in "while" statement? Is it about runloop or iOS8 has some features like UIPresentationController that will not allow this case? And how to fix this?
Thanks in advance.
I just hit this also. It seemes the UIPresentationController crashes if it's presenting view disappears before it is done using it. One fix is to keep the view controller around a little bit longer.
I got a very interesting problem here. My iPhone app has an UITabbarController as rootViewController in the AppDelegate.
If the app is opened the first time, it must be configured basically. For this purpose I create an UINavigationController and tell the tabbarController to present it modally:
firstRun = [[firstRunViewController alloc] init];
navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
When the configuration is done, I'd like to get rid of the firstRunViewController. I'm using this technique very often, using -dismissModalViewControllerAnimated:.
But in this constellation this doesn't work. It doesn't matter from what controller I'm calling the dismiss.
I tried it via the tabbarController, the rootViewController, the currently active viewController, of cause self and several other controllers.
EVERY TIME I call -dismissModalViewControllerAnimated: I get this exception:
'UIViewControllerHierarchyInconsistency', reason: 'presentedViewController for controller is itself on dismiss for: <UINavigationController:…
Can anybody help? Thanks in advance, with kind regards, Julian
EDIT
In my AppDelegate I'm using a UITabbarController as rootViewController for the main window:
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
Then I'm creating an UINavigationController and tell the UITabbarController to present the modalViewController:
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
When I now call -dismissModalViewControllerAnimated: on the firstViewController I'm getting the error from above.
In my opinion you are abusing UITabbarController. This class, even though a subclass of UIViewController, does not really use much of the UIViewController infrastructure.
What you want is a slight extension of what you have now. Create a new UIViewController subclass in your appDelegate, and add it as the single object to an array, and set the tabBar's viewControllers to this array. Set your subclass' hidesBottomBarWhenPushed to YES so it hides the tab bar when it becomes visible.
Now your app will launch and your UIViewController subclass will become the frontmost view. You can make this view the one you wanted to present modally, or you can present that view from your subclass using some kind of animation. Oh, and if you use the launch view as the background image for your subclass, you can really make this a smooth transition - I do this now.
When your modal view is done, then you can instantiate whatever views you want to then display, and set the UITabBarController to use those views with tabBarController.viewControllers (or the animated version). Poof, you UIViewController will get replaces (and under ARC just disappear).
I don't have a chance to test my hypothesis, but I suspect that this issue could depend on the fact that you are presenting the modal view too early, whereby too early means before the main window has had the chance to set up the tab bar controller. So, I would suggest this changes:
create a method to instantiate your navigation controller:
- (void)initializeAndPresentNavigationController {
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
}
instead of presenting the navigation controller directly from appDidFinishLaunching, call the above method asynchronously:
[self performSelector:#selector(initializeAndPresentNavigationController) withObject:nil afterDelay:0.0];
Here the trick of calling the method as I do in 2 is that the call to initializeAndPresentNavigationController will be simply pushed on the main loop, and executed after your app has had the possibility to build its initial UI.
Hope it works for you.
I finally found the answer myself!
I just couldn't see the wood for the trees! I'm quite happy right now! :)
I did really silly things: In the last viewController of the setup viewControllers I had to change the tabars viewControllers corresponding to whether the user is administrator or not. So I did:
appDelegate.tabBarController.viewControllers = [NSArray arrayWithObjects:appDelegate.readState,
appDelegate.navCtrl,
appDelegate.settings, nil];
You can see that I was adding the AppDelegate's "navCtrl" to the tabbar's viewControllers. So I was trying to dismiss a viewController I just added to the parentViewControllers (UITabbarController) sub-controllers.
Dismissing something I want to present just in the same moment is NOT advisable! :))
I'm trying to "bookmark" (sort of) an object from one UIViewController so that it then shows on a different UIViewController. Currently, the only way I can get this to work is if I either push to the UIViewController that will display the bookmarks or if I perform a segue which is basically the same thing.
Is there a different approach to this?
if you just want to send a variable (without loading the view). This is how I do it.
DetailViewController *detailvc = [[[DetailViewController alloc] init] autorelease];
detailvc.event = [self.fetchedResultsController objectAtIndexPath:indexPath];
And another type of segue I've been doing (without the need of the whole function) i just ask the storyboard to go...
[self.storyboard instantiateViewControllerWithIdentifier:#"detailViewController"];
Just don't forget to name the identifier in the sotyboard, properties, identifier.
Hope it helps...
I've been having some trouble re-learning everything with the storyboard as well.
I have an issue .
I have code that reads in RSS feeds, its navigation based.
RssFunViewController - > thats the view for the table (list of feeds)
NewsDetailViewController - > thats shows more information about the news feed which was selected by user (in a new view).
But when i try to use it in a tab-based navigation project it doesnt work. I just get the table of RSS feeds, When i click an item i dont see the detailed view.
I think my issue is the connection with the tab controller and my classes.
For my 3rd navigation tab I set RssFunViewController as the class.
My question is how do i connect my RSSFunViewController and NewsDetailViewController so when the user clicks the item I see the detailed view.
Heres my current connections in my tab controller:
www.freeimagehosting.net/uploads/535e439c7f.jpg
Thanks everyone.
Maybe I have to disappoint you, but iPhone coding has a very steep learning curve past the drag&drop and connect the dots phase, where you actually have to understand things and make them work using code.
Although the information you give is very limited, here's a brief outline of how the table click action could be handled.
The table should have it's delegate and data source connected to the right class (may be, but does not have to be the same class).
The delegate class should contain a method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
which will be called when a table entry is tapped. indexPath.row will then give the row number of the tapped entry.
In this method, you could present another view controller showing details, e.g. like:
NewsDetailViewController *ndvc = [[NewsDetailViewController alloc] autorelease];
ndvc.delegate = self;
[ndvc setFeedId:indexPath.row];
[ndvc initWithNibName:#"NewsDetailViewController" bundle:nil];
[self.navigationController pushViewController:ndvc animated:YES];
(assuming the NewsDetailViewController would have a setFeedId method etc.)
or you could have the NewsDetailViewController instantiated in your nib file so you could skip the alloc and initWithNibName steps, and put an "IBOutlet NewsDetailViewController *ndvc;" in the header file so you can connect them.
To remove the highlight from the tapped row, do
[tableView deselectRowAtIndexPath:indexPath animated:YES];
If you're working on a supplied project, you should be able to find lines like these already lying around. Good luck.
Whenever my app is rotated, only the viewController of which I've added his view as a subview to the mainwindow gets his interfaceOrientation property updated, the rest remains ignorant of the fact the device has been rotated.
Is it my responsibilty to notify other objects of the change, and if so, what's a nice way to do it?
I've looked into setting interfaceOrientation of my children-viewcontrollers but that's readonly.
Thanks in advance,
I found that calling
willRotateToInterfaceOrientation
and/or
didRotateFromInterfaceOrientation
of the view controller you are going to show worked for me. In my case I was using a Navigation Controller so it was easy to keep track of what was going to be shown to the user next. Below is some code from my project.
- (void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated {
[viewController willRotateToInterfaceOrientation:
[self interfaceOrientation] duration:0];
}