UIViewController removeFromSuperview error - ios

I have a UIViewController then when I longpress to self.view it will push a popup (MenuViewController). But when I try to remove popup by removeFromSuperview it still appears
You can see more detail of my problem with this http://www.youtube.com/watch?v=nVVgmeJEnnY
ViewController.m
#import "MenuViewController.h"
#interface ViewController () {
MenuViewController *menu;
}
....
- (void)viewDidLoad
{
....
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(albumButtonPressed : ) name:#"albumButtonPressed" object:nil];
....
}
....
-(void)albumButtonPressed : (NSNotification*) notification {
UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
photoPicker.delegate = self;
photoPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:photoPicker animated:YES];
}
...
-(void)handleLongPress:(UILongPressGestureRecognizer*)recognizer {
menu = [[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:nil];
if (self.imageView.image != nil) {
menu.imageAdded = YES;
}
[self.view addSubview:menu.view];
}
MenuViewController.m
-(IBAction)albumButtonPressed:(id)sender {
[self.view removeFromSuperview];
[[NSNotificationCenter defaultCenter] postNotificationName:#"albumButtonPressed" object:nil];
}

Setting aside my reservations about not applying proper view controller containment, the problem is that your handleLongPress will be called multiple times with different recognizer.state values, once as UIGestureRecognizerStateBegan and again as UIGestureRecognizerStateEnded. You should be checking the state of the gesture, e.g.:
-(void)handleLongPress:(UILongPressGestureRecognizer*)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded) {
menu = [[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:nil];
if (self.imageView.image != nil) {
menu.imageAdded = YES;
}
[self.view addSubview:menu.view];
}
}
Original Answer:
I'd suggest putting a NSLog or breakpoint at your code with the removeFromSuperview and see if you're even getting to that piece of code.
There are some clear problems here. Specifically, you're not adding added the view associated MenuViewController in handleLongPress properly. If you want a subview with it's own controller, you have to use containment (and that only works with iOS 5 and later). And in containment, you have critical methods like addChildViewController, etc. See Creating Custom Container View Controllers in the View Controller Programming Guide or see WWDC 2011 - Implementing UIViewController Containment. And, as an aside, you're also maintaining a strong reference to MenuViewController, so even if you succeeded in removing it's view, you'd leak the controller.
Spend a little time going through the containment documentation/video, and I think you'll want to revisit how you're presenting your menu. This is dense reading, but worth really understanding. Containment is powerful, but has to be done right.

[self.view removeFromSuperview];
what do you mean by this?????? removing the main view!!!!

Instead of directly using
[self.view removeFromSuperview];
use
[[self.view.superview subviews] makeObjectsPerformSelector:#selector(removeFromSuperview) withObject:self.view];

Related

UINavigationController pushes several of the same viewController

I have a UIButton in my app that when pressed it shows the next view controller. Sometimes the UI locks up and the app freezes for a moment due to background processes. When this happens the user might tap the button multiple times because nothing happened immediately on the first tap, and when this occurs the UINavigationController pushes the ViewController again a bunch of times on top of itself, so that you have to go back several times to get back to home. Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
self.pushVCButton.multipleTouchEnabled = NO;
}
- (IBAction)pushVCButtonPressed:(id)sender {
self.pushVCButton.enabled = NO;
ViewController *viewController = [[ViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
self.pushVCButton.enabled = YES;
}
How do I get this to never push multiple instances of viewController?
You should really try to make the background process run not on UI thread, but if you can not try setting the button enabled to yes only when view did disappear or listen for completion of push animation:
- (IBAction)pushVCButtonPressed:(id)sender {
self.pushVCButton.enabled = NO;
ViewController *viewController = [[ViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
// Hack: wait for this view to disappear to enable the button
//self.pushVCButton.enabled = YES;
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated]
self.pushVCButton.enabled = YES;
}
Also make sure that the action is not called twice.

ios - How can I dismiss(close) the load UIViewController on the window

I have a question, I want to build popup view like the UIAlertView,
I create two UIViewController in the storyboard(note: there are not segue),and Root UIViewController will load the UIViewController view popup.
I create two UIViewController to edit the UIView, because I want to use the storybaord to edit my complex UIView in the feature.
Then I put the container view on the RootViewController and there are two button in the container view.(my structure as below:)
When I click the pop up green button(with button name popupGreenBtn), It can correct addSubview on the UIWindow.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"ContainerViewController view didload");
appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
secondGreenVC = (SecondGreenViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:#"SecondGreenViewController"];
thirdRedVC = (ThirdRedViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:#"ThirdRedViewController"];
}
- (IBAction)popupGreenBtnAction:(id)sender {
[appDelegate.window addSubview: secondGreenVC.view];
[appDelegate.window bringSubviewToFront:secondGreenVC.view];
}
- (IBAction)popupRedBtnAction:(id)sender {
[appDelegate.window addSubview: thirdRedVC.view];
[appDelegate.window bringSubviewToFront:thirdRedVC.view];
}
When I click the button , it can correct popup on the window:
But now , When I click the SecondGreenViewController and ThirdRedViewcontroller background view(just transparent dark black), I want to close the popon the view(secondGreenVC.view or thirdRedVC.view).
I had try to add the code in the SecondGreenViewController class below:
#implementation SecondGreenViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapAction:)];
[_secondBaseView addGestureRecognizer:tap];
}
-(void) tapAction:(UITapGestureRecognizer*) recognizer
{
[self removeFromParentViewController];
// [self dismissViewControllerAnimated:NO completion:nil];
NSLog(#"tap in SecondGreenViewController");
}
#end
There are not effect to close the UIViewController.
How can I close the Popup window(the UIViewController) when I click the dark black part?
(If you want to more info, please tell me or you can see my this simple project from github https://github.com/dickfalaDeveloper/PopUpViewDemo )
Thank you very much.
-(void) tapAction:(UITapGestureRecognizer*) recognizer
{
thirdViewcontroller.hidden=YES;
}
I resolve the problem. But I don't know have any best answer.
My method is in the popupGreenBtnAction actin.
change the code to:
appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
secondGreenVC.modalPresentationStyle = UIModalPresentationCustom;
[appDelegate.window.rootViewController presentViewController:secondGreenVC animated:NO completion:nil];
Then in the SecondGreenViewController storyboard,
Drag an other UIView do base UIView and set the UIView IBOutlet(now I name with"secondBaseView").
at SecondGreenViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapAction:)];
[self.secondBaseView addGestureRecognizer:tap];
}
-(void) tapAction:(UITapGestureRecognizer*) recognizer
{
[self dismissViewControllerAnimated:NO completion:nil];
}
That is Ok to show the modal and dismiss the modal UIViewController.

UIScrollView disabled after UINavigationController push and pop

I have looked at the other answers to this question, and none of them have helped.
I have a UIScrollView in my very simple scene, embedded like this:
I use this code to make sure the scroll view will actually scroll, based off of this answer.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self resizeScrollView];
}
- (void) viewDidLayoutSubviews {
[self resizeScrollView];
}
- (void)resizeScrollView
{
_scrollView.scrollEnabled = YES;
[_scrollView setContentSize:_innerView.frame.size];
}
- (IBAction)cameraButtonPressed:(id)sender {
UIViewController *vc = [UIViewController new];
[self.navigationController pushViewController:vc animated:YES];
}
The problem is that scrolling doesn't work after I've pushed and popped the new ViewController (Which originally was an image picker btw).
I don't know why this worked, but I wrapped everything in another view, and it's perfect now.

How to improve efficiency with AddChildViewController

I am using AddChildViewController and adding a CalendarViewController, here is the code to add it
- (void)calButtonClicked
{
m_calViewController = [[CalendarViewController alloc]initWithNibName:#"CalendarViewController" bundle:nil];
[self addChildViewController:m_calViewController];
[[self view] addSubview:[m_calViewController view]];
[m_calViewController didMoveToParentViewController:self];
}
Now this CalendarViewController I have a function to create the calendarUI , I have written it in
- (void)viewDidLoad
{
[self createCalendarUI];
}
Now whenever I click on the button to open this ViewController , method viewDidLoad is called everytime and it takes time to create the UI. And because of that , my app is becoming slow.
So is their any way so that my UI is created only once, So that I can improve the efficiency
Regards
Ranjit.
if you just want to reuse CalendarViewController
try reuse CalendarViewController's view and do not alloc CalendarViewController in calButtonClicked each time.
- (void)calButtonClicked
{
if(!m_calViewController){
m_calViewController = [[CalendarViewController alloc]initWithNibName:#"CalendarViewController" bundle:nil];
[self addChildViewController:m_calViewController];
}
[[self view] addSubview:[m_calViewController view]];
[m_calViewController didMoveToParentViewController:self];
}

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.

Resources