EXC_BAD_ACCESS at removeFromSuperview - using ARC - objective-c

In one of my ViewControllers (ViewController A), I have the following code:
AlertViewController *aViewController = [[AlertViewController alloc] initWithNibName:#"AlertViewController" bundle:nil];
[self.view addSubview:[aViewController view]];
[self.view bringSubviewToFront:[aViewController view]];
And in AlertViewController, I have a button and when the user clicks on it, I have:
[self.view removeFromSuperview];
Whenever I click the button, the result is EXC_BAD_ACCESS.
I'm unable to figure out the problem. My project is using ARC and ViewController A is part of a navigation controller stack if that info helps.

The problem here is that the UIView doesn't own its UIViewController. In the first block of code you held the UIView around by adding it to a subview, but let the UIViewController go away. The UIView from a UIViewController is special, you can't let this happen.
Make sure the UIViewController that created the UIView lives as long as the view does.

Related

removeFromParentViewController doesnot update UINavigationbar

I want to remove all the viewcontrollers from UINavigationController. So I am using this code.
for (UIViewController* controller in navigationController.viewControllers) {
[controller removeFromParentViewController];
}
After that I create an new viewController and push it.
UIViewController* newVC=[[UIViewController alloc] init];
[navigationController pushViewController:newVC animated:YES];
Issue is all the viewcontrollers popout perfectly and adding newVC but on pushing newVC the navigationbar is getting a back button and title of newVC. On clicking back button it animates to the navigationbar of oldVC with title of oldVC that I have already removed in above loop;
removeFromParentViewController is a UIViewController method, so it's normal it has nothing to do with UINavigationBar
In the case of a UINavigationController the popViewControllerAnimated: method handles the removeFromParentViewControllerpart for you, along with navigation bar.
you can directly update the whole array of viewControllersof UINavigationController, calling `setViewControllers:animated:
see Replacing rootView in navigationController
[navigationController setViewControllers:[NSArray arrayWithObject:newVC]];

UIView inside a UIViewController or better way to do it?

I have a problem on how to properly do a certain kind of action.
The image below shows a UIViewController, but the second part of the view is a custom UIView (the one with the profile pic, name and Show View button).
The subclassed UIView is allocated using this code:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
[self.view addSubview:profileView];
The problem is of course, that the button on the UIView can't show any view, since it's only the UIViewController that can push another ViewController to the window(correct?).
The UIView is used in several places in the app and needs to be added easily and have the same behavior across the application.
This worked great until I added the button, and I'm starting to think I've made this wrong, and there has to be a better way to do it (maybe change the UIView to something else?).
I was thinking I should be able to call:
self.superview
And then somehow get the ViewController so I can push another ViewController into the view hierarchy, but nope.
Any suggestions and a tips on how to do this correctly?
UPDATE:
I have no idea on how to push another UIViewController from the button.
What should I do in this method when pressing the button in the UIView:
- (void) showViewButtonTouched:(UIButton*)sender {
GPProfileSocialFriendsViewController *friendsSettings = [[GPProfileSocialFriendsViewController alloc] init];
}
How do I push GPProfileSocialFriendsViewController?
Your - (void) showViewButtonTouched:(UIButton*)sender method should be in your controller and would probably be better named - (void) showView:(UIButton*)sender or - (void) showProfile:(UIButton*)sender so it clearly denotes what it does (not how you got there).
It's not the view's responsibility to manage transitions from a state to another. If you move your method to your controller, your problem is no more (you can easily access self.navigationController or push directly if you don't have an navigation controller like this:
[self presentViewController:vcThatNeedsToBePushed animated:YES completion:nil];
I think you can create weak reference in GPProfileView on UIViewController. Like this:
#property (weak, nonatomic) UIViewController *rootController;
when you create GPProfileView, assign rootController-property:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
profileView.rootController = self; // if view created in view controller
[self.view addSubview:profileView];
and in implementation of button selector:
self.rootController push... // or pop
May be this not correct, but you can try
You could let the view controller push the next view controller when the button is pushed. The view controller can add a target/action on the button, so that the action method in the view controller is called on the touch up inside event.

iOS - Unit testing a viewController?

So I am unit testing my ViewController, and as soon as it calls viewDidLoad my test crashes, because in my code I try to add a barButtonItem to my navigationBar and it does not exist.
How can I make this separation while unit testing my viewController
EDIT:
It crashes on the second line, any suggestions? so it's not a navigationBar because at this point I haven't added my toolbar to my navigationBar yet
UIToolbar *toolBar = [[UIToolbar alloc] init];
[toolBar setItems:items animated:NO];
EDIT: I am running SenTestCases and I get no exception traces
You need to ensure that the controller has constructed it's view first. Accessing the view property on UIViewController should trigger the creation of the UIView it's controlling: [mycontroller view].

Objective C: How to present modal view controller from appdelegate?

I am in the appdelegate of my application. How can I add a modal view controller in the "didfinishlaunching" method?
I tried the following but did not work
SomeViewController *vc = [[SomeViewController alloc]init];
[self.tabController.navigationController presentModalViewController:vc animated:NO];
EDIT:
I changed my implementation to the following
self.tabController.selectedViewController
= [self.tabController.viewControllers objectAtIndex:0];
SomeViewController *vc = [[SomeViewController alloc]init];
[self.tabController.selectedViewController presentModalViewController:vc animated:NO];
I checked that the 'selected view controller' is not null... however I am still not able to get the output I needed. Is there anything I am missing?
Assuming tabController and navigationController are not nil, the applicationDidFinishLaunching may be too soon to display the modal view controller.
Make sure you put that code after you make the window key and visible. [self.window makeKeyAndVisible];
If that does not work try listening for the UIWindowDidBecomeKeyNotification for that window
You can try delaying presentation of that modal a few seconds using performSelector:withObject:afterDelay:

iPad UIPopoverController does not go over inputView in UITextView

I am trying to set up a popover to point to a UIButton in a view that is used as a "inputView" to a UITextView. I can get everything to work and the correct data is going into the UIPopoverController. But it is exhibiting a behavior that is not what I expected. So here is what I have. The following method is written in a UIView subclass that is the inputView of the UITextView and is also the view in which the button resides.
- (IBAction)buttonTouchDown:(id)sender {
UIButton *button = (UIButton *)sender;
MyPopoverContentController *controller = [[MyPopoverContentController alloc] initWithNibName:#"MyNib" bundle:nil];
[controller setContentSizeForViewInPopover:CGSize(320.0, 304.0)];
self.popupController = [[UIPopupController all] initWithContentViewController:controller];
[self.popupController presentPopoverFromRect:[button frame] inView:self permittedArrowDirectoions:UIPopoverArrowDirectionDown animated:YES];
}
Now, I would expect the popover to float over the inputView and the pointer would touch the button I've placed into the view. But it does not. In the 'X' origin the popover point is correct. But it appears the UIView when acting as a input view it won't allow the popover to move down over the inputView to the UIButton. Am I overlooking something?
Thanks for any help,
Rob
It's been a while since I visited this question. I turned this in to Apple and it is a bug. They are working on it.
Try:
[self.popupController presentPopoverFromRect:button.bounds inView:button permittedArrowDirectoions:UIPopoverArrowDirectionDown animated:YES];