Modal transition - One of the views is seemingly getting deallocated - ios

In my app, I do a search asynchronously. When that completes my mapViewController with pins for the locations is displayed. 2 seconds after that, I do a modal transition over to a listViewController. I set the backgroundcolor like this:
self.view.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.65];
Making it possible to see the map behind it.
The problem is this: Less then a second after the listView appears you can see the map in the background for a second before it goes away. What I can see in the background now, is the mainViewController the app starts with.
it looks like this:
Less than a second later:
Any help/explanation would be greatly appreciated.

Your view is still transparent, but once your modal controller is at the top of the stack, the view behind it is hidden.
Try using :
yourController.modalPresentationStyle = UIModalPresentationCurrentContext;
[yourController present...];

This code seems to work. I hope it will help.
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
MKMapView *mapView = [MKMapView new];
[self.view addSubview:mapView];
mapView.frame = self.view.bounds;
UIGestureRecognizer *gestureRecognizer = [UITapGestureRecognizer new];
[gestureRecognizer addTarget:self action:#selector(displayTransparentVC)];
[self.view addGestureRecognizer:gestureRecognizer];
}
-(void)displayTransparentVC
{
UIViewController *vc = [TransparentViewController new];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:YES completion:^{
}];
}

Related

presentViewController:animated:completion: does not animate View Controller into view

I am trying to debug a really weird issue in the following code:
if(condition1) {
ImageViewController* imageViewer = [[ImageViewController alloc] initWithImageData:tappedItem];
[self presentViewController:imageViewer animated:YES completion:^{
[imageViewer loadImage];
}];
}
else if(condition2) {
DocumentViewController* docViewer = [[DocumentViewController alloc] init];
[self presentViewController:docViewer animated:YES completion:nil];
}
In other words, depending on the state of condition1 and condition2, one of two subclasses of UIViewController will be displayed modally to the user.
In the second case all is well, but in the first the view controller is not presented with the usual animation that shows it sliding in from the bottom of the screen. Instead, after a brief delay, it just shows up all of a sudden, covering the entire screen. Another oddity is that in the dismissal animation, the image view inside the view controller is transparent.
Removing the completion block has no effect. Replacing my view controller with an instance of UIViewController also has no effect, other than demonstrating that for some reason, animations don't work for UIViewController instances either.
Thinking that maybe I did something wrong in viewDidLoad etc, I tried commenting out the view load/appear methods but to no avail.
Pushing the view controller onto the nav stack is not an option because the app has a tab bar and I don't want to be visible.
update
Replacing my instance of ImageViewController with a DocumentViewController does result in an animation. The question now becomes: what could I have done in ImageViewController to mess up the animation?
I've found a solution but I still have no idea what the real cause was.
The fix was to set a background color for the view of the UIViewController being displayed modally in its viewDidload method e.g.
self.view.backgroundColor = [UIColor grayColor];
If I ever figure out what really happened, I will post here.
How about presenting the view controller on the tab bar controller:
if(condition1) {
ImageViewController* imageViewer = [[ImageViewController alloc] initWithImageData:tappedItem];
[self.tabBarController presentViewController:imageViewer animated:YES completion:^{
[imageViewer loadImage];
}];
}
else if(condition2) {
DocumentViewController* docViewer = [[DocumentViewController alloc] init];
[self.tabBarController presentViewController:docViewer animated:YES completion:nil];
}
It happened to me as well.. changing the background colour didn't really help.
I did the following - it turns up to be quite nice:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:NO];
self.view.userInteractionEnabled = FALSE;
self.view.hidden = TRUE;
self.navigationController.navigationBar.alpha = 0;
}
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:NO];
float width = self.view.frame.size.width;
float height = self.view.frame.size.height;
self.view.frame = CGRectMake(0, height, width, height);
self.view.hidden = FALSE;
[UIView animateWithDuration:0.7f animations:^{
self.view.frame = CGRectMake(0, 0, width, height);
self.navigationController.navigationBar.alpha = 1;
} completion:^(BOOL finished){
self.view.userInteractionEnabled = TRUE;
}];
}
Setting the background color works for me in iOS 8.
Also uncheck the opaque setting in the Interface Builder works!

Scrolling not working after UIImagePickerController

In my app scrolview is made active using the following code.
scroll.contentSize = CGSizeMake(320, 760);
[scroll setScrollEnabled:YES];
[scroll setCanCancelContentTouches:NO];
scroll.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scroll.clipsToBounds = YES;
scroll.pagingEnabled = NO;
scroll.autoresizesSubviews=YES;
[scroll setContentMode:UIViewContentModeScaleAspectFill];
But after using the UIImagePicker/controller.ie. after selecting the image from the phone gallery,scrolling is not working. The above code is written in the viewWillAppear section.Can anyone help me so that I can make scrolling working even after the UIImagePickerController? Thanks for any help ...
I had a similar issue lately. Mine was in having a ViewControllerA which was a parent to ViewControllerB which in turn is a parent of ViewControllerC1..N. ViewControllerB has a scrollview which scrolls views of ViewControllerC1..N. It is reproducible only on iOS9.
If I present UIImagePickerController to get images from gallery (sourceType == UIImagePickerControllerSourceTypePhotoLibrary) from ViewControllerA after dismissing it scrollview of ViewControllerB stops scrolling correctly.
I have made a workaround. I push dummy view controller into navigation stack, then present image picker and then pop back to ViewControllerA.
This way it works.
It seems like in iOS9 UIImagePickerController messes up something with touch events in its presenting view controller.
replace your dismissing code like this and check:
[picker dismissViewControllerAnimated:YES completion:^{
scroll.contentSize = CGSizeMake(320, 760);
[scroll setScrollEnabled:YES];
[scroll setCanCancelContentTouches:NO];
scroll.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scroll.clipsToBounds = YES;
scroll.pagingEnabled = NO;
scroll.autoresizesSubviews=YES;
[scroll setContentMode:UIViewContentModeScaleAspectFill];
}];

UINavigationController as child of UINavigationController

I don't know if the title explains the question itself but here it is ...
I have a UINavigationController which is the parentViewController of a UINavigationController. The thing is the childViewController behaves strange, when I add it as a child it first has the gap for the statusBar (it doesn't occupy the entire screen) and if I "solve" that "bug" by hiding and showing the navigationBar, the gap goes away but now the child doesn't respect the frame I set manually.
Then I tried to continue and when I presented a modal on the child and dismiss it, the entire child goes away ...
What would be wrong there? The parent-child relationship with both containers or what?
Thanks in advice
EDIT: Here's an example project showing the strange behavior
http://www.mediafire.com/?8saa68daqfkf335
EDIT 2: I found a solution actually and I didn't find it really clear on Apple Docs, it says the childViewControllers take its frame from the parentViewController they belong to, but it doesn't say that if the parentViewController "reappears" (like a push on it) the childViewControllers get resized again by the parentViewController frame ... Hope this helps anyone
I believe it would be better to present the second navigation view controller as a modal view controller.
For example, replace your current presentController selector with something like:
- (void)presentController:(id)sender {
ChildViewController1 *cvc = [[ChildViewController1 alloc] initWithNibName:#"ChildViewController1" bundle:nil];
nc3 = [[UINavigationController alloc] initWithRootViewController:cvc];
nc3.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:nc3 animated:YES completion:nil];
UIBarButtonItem *i = [[UIBarButtonItem alloc] initWithTitle:#"X" style:UIBarButtonItemStyleBordered target:self action:#selector(close)];
cvc.navigationItem.leftBarButtonItem = i;
}
Then, your close selector could become:
- (void)close {
[nc3 dismissViewControllerAnimated:YES completion:nil];
}
(though I'd recommend moving the creation of the button and handling the close actually in ChildViewController1.m).
Of course, this would take all the creation of the navigation controller off ViewController.m's viewDidLoad selector:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blueColor];
UIButton *b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
b.frame = CGRectMake(0, 100, 100, 40);
[b setTitle:#"present" forState:UIControlStateNormal];
[b addTarget:self action:#selector(presentController:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:b];
}
Hope it works!

Message sent to dealloc UIViewController with error: EXC_BREAKPOINT (code=EXC_I386_BPT)

I have an app that uses a transition file to flip from page to page. I am using ARC and works just fine on 5.1, but crashes all the time on 4.3 simulator. Looking at the thread and the extended detail from instruments, it points to 2 lines of code (shown below) with the error: EXC_BREAKPOINT (code=EXC_I386_BPT). Looks like the UIViewController is being deallocated. Not sure how to fix this. Thanks in advance for any help you can offer!
#synthesize containerView = _containerView;
#synthesize viewController = _viewController; //ERROR LINE#1
- (id)initWithViewController:(UIViewController *)viewController
{
if (self = [super init])
{
_viewController = viewController;
}
return self;
}
- (void)loadView
{
self.wantsFullScreenLayout = YES;
UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.view = view;
_containerView = [[UIView alloc] initWithFrame:view.bounds];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self.view addSubview:_containerView];
[_containerView addSubview:self.viewController.view];
}
- (void)transitionToViewController:(UIViewController *)aViewController
withOptions:(UIViewAnimationOptions)options
{
aViewController.view.frame = self.containerView.bounds;
[UIView transitionWithView:self.containerView
duration:0.65f
options:options
animations:^{ [self.viewController.view removeFromSuperview];
[self.containerView addSubview:aViewController.view];}
completion:^(BOOL finished)
//ERROR LINE#2 { self.viewController = aViewController;}];
}
You should not be transitioning views in and out from underneath their respective view controllers. You might get it to work, but it's fragile, at best.
If you want to future-proof your code, you should be transitioning between view controllers and let them handle their own views, but wrap that in the desired animation if you don't like the default animation. So, you should either:
Just do simple presentViewController or pushViewController to go to the next controller and dismissViewController or popViewController to return; or
In iOS 5, you can do your own container view controller (see session 102 in WWDC 2011 or see the discussion of view controller containment in the UIViewController reference) and then you can transitionFromViewController.
If we knew more about your app flow, why you're doing what you're doing, we can probably advise you further.

iOS: display modal view over the top of a UIWebView

Is it possible to display a modal view over the top of a UIWebView? I have a UIViewController that loads a WebView. I then want to push a Modal View Controller over the top so that a modal view covers up the WebView temporarily...
The WebView is working fine; here's how it's loaded in the View Controller:
- (void)loadView {
// Initialize webview and add as a subview to LandscapeController's view
myWebView = [[[UIWebView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
myWebView.scalesPageToFit = YES;
myWebView.autoresizesSubviews = YES;
myWebView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
myWebView.delegate = self;
self.view = myWebView;
}
If I attempt to load a Modal View controller from within viewDidLoad, however, no modal view appears:
- (void)viewDidLoad {
[super viewDidLoad];
// Edit dcftable.html with updated figures
NSMutableString *updated_html = [self _updateHTML:#"dcftable"];
// Load altered HTML file as an NSURL request
[self.myWebView loadHTMLString:updated_html baseURL:nil];
// If user hasn't paid for dcftable, then invoke the covering modal view
if (some_condition) {
LandscapeCoverController *landscapeCoverController = [[[LandscapeCoverController alloc] init] autorelease ];
[self presentModalViewController:landscapeCoverController animated:YES];
}
}
I suspect that there's something that needs to be done with the UIWebView delegate to get it to receive the new modal view...but can't find any discussion or examples of this anywhere...again, the objective is to invoke a modal view that covers over the top of the WebView.
Thanks for any thoughts in advance!
I ran into this same problem. Moving the presentModalViewController call from viewDidLoad to viewDidAppear did the trick.
I couldn't get it to work in viewDidLoad either, but I got it to work in a different method. Here's what I did:
- (void)viewDidLoad {
...
if (some_condition) {
[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(showModal) userInfo:nil repeats:NO];
}
}
- (void)showModal {
LandscapeCoverController *landscapeCoverController = [[[LandscapeCoverController alloc] init] autorelease ];
[self presentModalViewController:landscapeCoverController animated:YES];
}
Basically, it works if it's not being called in viewDidLoad. I wish I could explain why, I'm curious myself, but this should at least fix your problem.
Hope this helps!

Resources