A memory warning when replacing a root viewController with animation - ios

I could see that when i am replacing the root viewController without animation, everything works great, but when i am adding animation to it , its of course looks better, but it gives me a memory warning at the moment of the transition .
I am using iPad Air , I guess its because at that moment there are 2 views in the stack ??
Should i ignore it, or there is anything i can do ?
UIViewController *mainV=[self.storyboard instantiateViewControllerWithIdentifier:#"mainView"];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[UIView transitionFromView:delegate.window.rootViewController.view
toView:mainV.view
duration:0.75f
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished)
{
delegate.window.rootViewController=mainV;
}];

Placed your code in the dispatch_asynch and check:-
UIViewController *mainV=[self.storyboard instantiateViewControllerWithIdentifier:#"mainView"];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[UIView transitionFromView:delegate.window.rootViewController.view
toView:mainV.view
duration:0.75f
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished)
{
dispatch_async(dispatch_get_main_queue(), ^{
delegate.window.rootViewController=mainV;
});
}];
});

Related

Setting rootViewController causes black screen blink before is loaded

I got strange behaviour when setting the rootViewController programatically. I am using xib's only and here are scenarios of what I already tried.
When I use this code, there is a small blink of black screen before it loads VC correctly.
- (void)setRootVC:(UIViewController *)viewController {
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[UIView transitionWithView:window
duration:0.0
options:UIViewAnimationOptionTransitionNone
animations:^{ window.rootViewController = viewController; }];
}
When I use different function, it eliminates the blink, but there's another strange behaviour. I got bunch of textfields in the new VC and I am setting one of them to becomeFirstResponder in viewDidLoad method, but when the VC loads, the textFieldDidEndEditing is called, which is totally strange. Here's the code.
- (void)setRootVC:(UIViewController *)viewController {
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[UIView transitionFromView:window.rootViewController.view
toView:viewController.view
duration:0.0
options:UIViewAnimationOptionTransitionNone
completion:^(BOOL finished){
window.rootViewController = viewController;
}];
}
I am restricted with objective-C, so swift solutions will not be helpful. Thanks for the replies.
The blink is caused due to you are setting the rootViewController in completion where is it should be in animation block, so the code below might be helpful for you..
[UIView transitionWithView:self.window
duration:0.5
options:UIViewAnimationOptionTransitionNone
animations:^{ self.window.rootViewController = viewController; }
completion:nil];
Instead of using UIViewAnimationOptionTransitionNone you might want to add some transition effect so, you can use UIViewAnimationOptionTransitionCrossDissolve instead, it might look better..
Hope it helps.
Cheers.

iOS Changing rootViewController after login / logout process in Objective-C

I've read many question about this issue but I don't figure out what it doesn't work.
Basically I want to change my root controller after the user logged in the or logout from the app. I am also using the storyboard.
My problem is SILoginViewController dealloc's function is never called, in this controller I send Notification and the observer is not removed, so it mess up everything, and after several "login/logout" it receives several notifications.
My AppDelegate :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.window setFrame:[[UIScreen mainScreen] bounds]];
BOOL isLoggedIn = [[SIUser aUser] isLoggedIn]; // from your server response
NSString *storyboardId = isLoggedIn ? #"rootViewController" : #"navVcForLogin";
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardId];
return YES;
}
If the user was not logged in and he success the process a Notification is send, here is the handler where I want to change the rootViewController :
- (void)loginSuccessHandler:(id)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
SIRootViewController * vc = [sb instantiateViewControllerWithIdentifier:#"rootViewController"];
[UIApplication sharedApplication].keyWindow.rootViewController = vc;
}
This is the same process for the logout, and here is the notification's handler :
- (void)logoutHandler:(id)sender
{
UIWindow *myWindow = [(SIAppDelegate *)[[UIApplication sharedApplication] delegate] window];
SILoginViewController * vc = [sb instantiateViewControllerWithIdentifier:#"navVcForLogin"];
[UIApplication sharedApplication].keyWindow.rootViewController = vc;
}
The easiest is to show you directly the storyboard :
The implementation in the Storyboard could seems weird but I'm using https://github.com/romaonthego/RESideMenu
I followed their storyboard implementation.
The thing is the SILoginViewController dealloc's method is never called.
But by the way it is working fine, in appearance I mean, when I run the application the behaviour is the good one, but It is sure it will mess out later on.
UPDATE
And I guess it is the common behaviour but there is no transition when the root view controller is changed and there is a black screen for a really short time when the new controller is appearing.
Black screen resolved using : in my AppDelegate.m
- (void)changeRootViewController:(UIViewController*)newRootViewController
{
if (!self.window.rootViewController) {
self.window.rootViewController = newRootViewController;
return;
}
UIView *snapShot = [self.window snapshotViewAfterScreenUpdates:YES];
[newRootViewController.view addSubview:snapShot];
self.window.rootViewController = newRootViewController;
[UIView animateWithDuration:0.3 animations:^{
snapShot.layer.opacity = 0;
snapShot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
} completion:^(BOOL finished) {
[snapShot removeFromSuperview];
}];
}
RootViewController Switch Transition Animation
This probably kind of a duplicate question but I spent hours to figure out this problem.
[currentRootViewController willMoveToParentViewController:nil]; // notify the VC of movements
[self addChildViewController:newRootViewController]; //Add the new VC
[self transitionFromViewController: currentRootViewController toViewController: newRootViewController
duration: 0.15 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
newRootViewController.view.frame = currentRootViewController.view.frame;
}
completion:^(BOOL finished) { //Cleanup from the move
[currentRootViewController removeFromParentViewController];
[newRootViewController didMoveToParentViewController:self];
}];
The code for willMoveToParentViewController and didMoveToParentViewController will notify the ViewController of the changes, and should get your dealloc called, since there is now nothing holding onto the ViewController, unless you have a pointer to it somewhere, then you will need to nullify all your pointers to the code. The solution you tried is only half of what needs to go on to get the transition completed successfully.

How to make uiview fullscreen viewcontroller using custom transitions ios7

What i want to achieve is: after tapping a small view with some data i want to make it full screen and possibly make it to be a new vc.
For now I animate uiview to full screen with great success, but whole logic of this view is in it's "parent".
Is it possible to animate viewcontroller out of the uiview which is similar (for. eg. like in LayoutTransitions in Android SDK)?
Sample code of my uiview to full screen using autolayout:
sender.view.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:0.2
animations:^{
sender.view.frame = self.view.window.bounds;
} completion:^(BOOL finished) {
[((CSTicketView*)sender.view) showMenu];
}];
[[UIApplication sharedApplication]
setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationFade];
[[self navigationController] setNavigationBarHidden:YES animated:YES];
Let's move your sender view to Window as like below,
AppDelegate * appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
[appDelegate.window addSubview:sender.view];
[UIView animateWithDuration:0.2
animations:^{
sender.view.frame = self.view.window.bounds;
} completion:^(BOOL finished) {
[((CSTicketView*)sender.view) showMenu];
}];
Absolutely possible.
You can use the new view controller transitions model in iOS7.
I would definitely recommend a few resources to check on top of my basic explanation:
this
and this
I have some sample code for a demonstrator of this here
Ultimately you make a new view controller for the view you are transitioning to, and you also make an NSObject subclass that conforms to UIViewControllerAnimatedTransitioning which contains the code to transition between them. Sounds complex but if you watch the video I linked to and read the other reference it'll make total sense.

iOS switch rootViewController not working

I have a login view that checks to see if there are default settings, then syncs data. If there are no default settings, the view waits for the user to login. if there are settings and the data syncs correctly, it should switch to my split view.
The code works if the user enters their login information. It syncs the data, then switches the view. If the user is already logged in, it hits the function and doesnt switch the view.
Here is the code being called by both paths:
-(void)redirect{
NSLog(#"Redirect#");
UISplitViewController *split = [self.storyboard instantiateViewControllerWithIdentifier:#"orders_split"];
[self.view.window setRootViewController:split];
}
"Redirect#" shows in the log on the initial load if the user has already logged in once. I have confirmed that there are no sync errors, it hits the function but does not perform the switch.
I am moving from a standard view with nav controller to a splitview, so I cannot use a manual segue trigger.
try to use app delegate:
UISplitViewController *split = [self.storyboard instantiateViewControllerWithIdentifier:#"orders_split"];
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = split;
in my projects I do it with animation:
+(void)setRootController:(UIViewController*)controller
storyboard:(UIStoryboard*)storyboard{
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[UIView
transitionWithView:appDelegate.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^(void) {
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
appDelegate.window.rootViewController = controller;
[UIView setAnimationsEnabled:oldState];
}
completion:nil];
}

Present multiple Images in fullscreen

I'm looking for the name of the class Apple uses to present a number of Images in full screen (similar to the AppStore-App on iPad when you tap the preview images of any App. In the bottom of the view is a bar with little preview Images from all the Images).
If this is a public class, how is it called and is it available for iPhone as well?
Ok so I have created my own ImageFullScreenPresenter.
What is important for anybody trying to build their own ImageFullScreenPresenter is to make it a subclass of UIViewController.
PKImageFullScreenPresenter *pkImageFullScreen = [[[PKImageFullScreenPresenter alloc] initWithNibName:#"PKImageFullScreenPresenter" bundle:nil imageArray:myImageArray] autorelease];
AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
UIViewController *rootViewController;
if (DEVICE_IS_IPAD) {
//since the splitviewcontroller is the rootviewcontroller on ipad i set it as my temporary rootViewcontroller for ipad
rootViewController = appDel.splitViewController;
}
if (DEVICE_IS_IPHONE) {
//on iphone i need the tabbarcontroller as temporary rootviewcontroller
rootViewController = appDel.tabBarController;
}
//set the alpha to zero, so it can fade in animated
pkImageFullScreen.view.alpha = 0;
//save the temporary rootViewController, so I can set it back when dissmissing the ImageViewController
pkImageFullScreen.superViewController = rootViewController;
//hide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
//setting black backgroundcolor
[UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor blackColor];
//init the fullscreencontroller as rootview
[[UIApplication sharedApplication].keyWindow setRootViewController:[[[UINavigationController alloc] initWithRootViewController:pkImageFullScreen] autorelease]];
//smooth fade animation
[UIView animateWithDuration:.5f
animations:^(void){
pkImageFullScreen.view.alpha = 1;
}];
Doing so, allows me to present the ImageFullScreenPresenter on iPhone and iPad, no matter you are using a window-based app, a splitViewController on iPad or whatever.
When dismissing the ImageFullScreenPresenter i set the temporary saved rootViewController back with an animation:
- (void)closeView:(id)sender{
[UIView animateWithDuration:.5f
animations:^(void){
self.view.alpha = 0;
}completion:^(BOOL finished){
//show the statusbar again
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
//setting the statusbarstyle
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];
//set the backgroundcolor for the window
[UIApplication sharedApplication].keyWindow.backgroundColor = GLOBAL_TINT_COLOR; //my custom color vor all GUI Objects
//set the temporary rootViewController back
[[UIApplication sharedApplication].keyWindow setRootViewController:superViewController];
//sometimes the navigationbar hides the statusbar, the following two lines help me out
[[UIApplication sharedApplication].keyWindow.rootViewController.navigationController setNavigationBarHidden:YES];
[[UIApplication sharedApplication].keyWindow.rootViewController.navigationController setNavigationBarHidden:NO];
}];
}
I dont know if this is the right way to go, but it works perfectly finefor me. I do not have to worry abput any rotation issues like I would have when i directly add this to [UIApplication sharedApplication].keyWindow.
I hope this helps others who try do achieve the same :)

Resources