ViewController occasionally miss in responder chain? - ios

i meet a very strange thing today: that my custom ViewController occasionally miss in responder chain
first i have a custom UIView, with a UIButton as its subview, then i set the target-action as usual:
[closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
of course, i implement the closeButtonPressed method in my custom UIViewController
in most time, it just worked fine. but occasionally, my ViewController miss the tap event, and finally i found that , the tap event pass to the AppDelegate, and the closeButtonPressed method in AppDelegate is invoked!
i spent a whole day in this problem, and still don't know why. can you give me a clue? thanks a lot. following is the code, hope it can help:
the code to init and present my ViewController and View:
YLSRegisterStepOneViewController *step1Controller = [[YLSRegisterStepOneViewController alloc] initWithNibName:nil bundle:nil];
step1Controller.view = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
step1Controller.modalPresentationStyle = UIModalPresentationFormSheet;
step1Controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:step1Controller animated:YES completion:nil];
the code of the UIView:
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
closeButton.frame = CGRectMake(10, 10, 50, 50);
[closeButton setTitle:NSLocalizedString(#"button_close", #"") forState:UIControlStateNormal];
[closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:closeButton];
the code of the UIViewController:
-(void) closeButtonPressed
{
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];// to dismiss self
}
additional: aside the UIButton, there is a UITextField. when this problem happens, if i click the UITextField, then click the UIButton, UIViewController works fine

You set controller property of YLSRegisterStepOneView like this:
YLSRegisterStepOneViewController *step1Controller = [[YLSRegisterStepOneViewController alloc] initWithNibName:nil bundle:nil];
YLSRegisterStepOneView *step1View = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
step1Controller.view = step1View;
step1View.controller = step1Controller;
You add the button in YLSRegisterStepOneView's initWithFrame: method, don't you?
So [closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside]; self.controller here is still nil.
step1View.controller = step1Controller; is called after [closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
updated:
You say the responder chain confuses you, I think the problem is that you assign view controller's view property like this step1Controller.view = step1View; which is not recommended. If you want to use your custom view as viewcontroller's view, do this:
Override loadView method in viewcontroller.
You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.
- (void)loadView
{
YLSRegisterStepOneView *step1View = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
self.view = step1View ;
}

I don't see where you are setting the controller property of the custom view which you are passing here:
[closeButton addTarget:*self.controller* action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
I think if you create/set the controller property in your view it would solve the problem (unless you are already doing it but code is not here).

Related

Back button without using navigation controller in IOS

I haven't embedd navigation controller with my view controller. Now i'm using a code to go back to home screen to with the use of back button but there nothing appears, i don't know why. I don't want to use navigation controller in my vc. This is the code,
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"car_marker.png"]
style:UIBarButtonItemStylePlain
target:self.navigationController
action:#selector(popViewControllerAnimated:)];
self.navigationItem.leftBarButtonItem = backButton;
It should look like this only,
You will need to change your approach because you cannot pop without a navigation controller.
You should embed your viewcontroller into navigation controller and then you can hide with [[self navigationController] setNavigationBarHidden:YES animated:YES]; and then you can add any kind of custom button to perform pop action.
For adding a custom back button to your view
- (void)addCustomBackButtonToView
{
UIButton *backButton = [[UIButton alloc] initWithFrame: CGRectMake(20, 20, 44.0f, 30.0f)];
[backButton setImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[backButton addTarget:self action:#selector(popVC) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
}
- (void) popVC{
[self.navigationController popViewControllerAnimated:YES];
}
You can hide your navigation controller by below code self.navigationController.navigationBar.isHidden = true
and use swipegesture option to move back, even though you have to use navigation controller,#iPeter has a valid point.
1) Add two ViewControllers make first as initial controller(entry point).
2) Add view on both ViewController with size you wish to have.
3) Add buttons on both views as subviews.
4) create segue from firstButton ->(use show) -> second controller.
5) From second ->(use show) -> first controller.
see the image below-:
This is not preferred way of doing pop/push. You must use Navigation Controller(that works like a stack for controllers you push) that will provide you default Back button or you can create custom .
You can not push or pop view controllers as you are not using the Navigation controller. Try using Present & dismiss controller which can called from any controller Instace.
Step 1 : Present to " Controller which is shown with no navigation bar but back button"
[self presentViewController:#"<ViewControllerToBePresented>" animated:NO completion:nil];
Step 2: add backBatton in ViewDidLoad
-(void)addBack{
UIButton *backBtn = [[UIButton alloc] initWithFrame: CGRectMake(20.0f, 20.0f, 50.0f, 30.0f)];
[backBtn setTitle:#"back" forState:UIControlStateNormal];
[backBtn addTarget:self action:#selector(dismissViewController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backBtn];
}
Step 3: Dismisscontroller to go back to previous scene
-(void) dismissViewController{
[self dismissViewControllerAnimated:NO completion:nil];
}

UIButton target action inside custom class

I've been struggling with a bug, and I found a work-around, but I'd like to understand what is exactly going on. it has something to do with UIButton target actions misfiring depending on different subview hierarchies, inside a subclass.
Brief summary: I have a subclass of NSObject with a UIView property object, a UIButton attached to it, and a target added to the button calling a function inside the subclass. Inside the main ViewController, I init the subclass and add its view to the view stack, click the button, and it throws me to main.mm with the error - EXC_BAD_ACCESS, gives me little feedback. so the hierarchy looks like this:
-CustomClass
--UIView <-this is added as a subview to the View Controller
---UIButton (onRelease calling a function)
so I fixed it by changing the custom class to be a subclass of UIView instead of NSObject, then add its #property UIView to be a subview of the custom class (and the button is still attached to the subview), and then in the main View Controller, I add the custom class itself as a subview, not the class's subview property object. then the button successfully calls the function. so the new arrangement looks like this:
-CustomClass (now UIView) <-this is added as a subview to the View Controller
--UIView <-this is added as a subview to CustomClass
---UIButton (onRelease calling a function)
then, i realized i can just keep the CustomClass a subclass of UIView for both instances, the problem persists with the original setup if everything else is unchanged.
okay, more detail, here's code:
CustomClass:
.h
#interface Temp : UIView
#property UIView *subview;
#property UIButton *but;
#end
.m
-(id) init{
self = [super initWithFrame:[[UIScreen mainScreen] bounds]];
if(self){
_subview = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//[self addSubview:_subview]; // FOR THE FIX
_but = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_but setTitle:#"OKAY" forState:UIControlStateNormal];
[_but setBackgroundColor:[UIColor blackColor]];
[_but setFrame:CGRectMake(50, 50, 200, 200)];
[_subview addSubview:_but];
[_but addTarget:self action:#selector(pageTurn) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void) pageTurn{
NSLog(#"WORKS");
}
inside view controller:
Temp *temp = [[Temp alloc] init];
[self.view addSubview:temp.subview];
//[self.view addSubview:temp]; // FOR THE FIX, instead of above line
Who's holding onto temp?
If temp isn't referenced by anyone then it's released. At that point the target is zombie and of course you will crash. temp.subview is being held by self.view.
In the second setup, adding temp as a subview of self.view keeps a reference to it.
You can fix this by adding a Temp * property in the view controller.
self.temp = [[Temp alloc] init];
[self.view addSubview:self.temp.subview];
You're messing with all kinds of view hierarchy stuff you don't need to, which is likely the cause of the problem. I created a Test UIView subclass that had a UIButton instance variable that I added as a subview in the Test object, there's no need to add another view as a subview and then add the button to the subview, and then in your view controller add the button's subview to the view - it's WAY more complicated than it needs to be.
In a nutshell - Create the Temp UIView, add the button as a subview, then in your view controller class add the Temp UIView as a subview. Simple as that, here is the code:
- (id)init {
self = [super initWithFrame:[[UIScreen mainScreen] bounds]];
if(self){
_but = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_but setTitle:#"OKAY" forState:UIControlStateNormal];
[_but setBackgroundColor:[UIColor blackColor]];
[_but setFrame:CGRectMake(100, 100, 200, 200)];
[_but addTarget:self action:#selector(pageTurn) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_but];
}
return self;
}
- (void)pageTurn {
NSLog(#"WORKS");
}
Then added an instance to my view controller:
Test *temp = [[Test alloc] init];
temp.backgroundColor = [UIColor redColor];
[self.view addSubview:temp];
This was the result:

How to dismiss IOS ViewController from a toolbar added to the view

I have a ViewController that contains a textfield. When the user begins editing the text, I want to display
a ViewController that the user can use to select the font for the textfield. I am using Xcode 5 with
storyboards and compiling for IOS 7. This is where I present the view controller...
- (void)textViewDidBeginEditing:(UITextView *)textView
{
FTViewController *fontSelector = [[FTViewController alloc] init];
[self presentViewController:fontSelector animated:YES completion:nil];
}
I am using a Cocoapods project called FTFontSelector to pick the font. In the FTViewController that gets
presented, I have the following code that runs when the view controller loads. This code adds a UIToolbar
with two buttons, one of which I would like to be used to dismiss the view controller, but all of the
attempts I have made at making this happen have not worked.
- (void)loadView;
{
CGRect frame = [[UIScreen mainScreen] applicationFrame];
self.textView = [[UITextView alloc] initWithFrame:frame];
self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.textView.textAlignment = NSTextAlignmentLeft;
self.textView.font = [UIFont systemFontOfSize:FONT_SIZE];
self.textView.text = #"Hello World!";
self.changeFontButton = [[UIBarButtonItem alloc] initWithTitle:#"Font"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(changeFont:)];
self.dismissFontButton = [[UIBarButtonItem alloc] initWithTitle:#"Dismiss"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(dismissFont:)];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(frame), 44)];
toolbar.tintColor = [UIColor lightGrayColor];
toolbar.translucent = YES;
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
toolbar.items = #[self.changeFontButton, self.dismissFontButton];
self.textView.inputAccessoryView = toolbar;
self.view = self.textView;
}
This is the method I call to dismiss the view controller that I need help with. I have commented out
what I have tried.
- (void)dismissFont:(id)sender;
{
[self.textView resignFirstResponder];
// This crashes!
//[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
}
I suspect part of my problem is that there is no navigation controller in my presented view controller,
but when I tried to add one, the text went behind the view (I could see a few pixels of the top of the text),
and there was no back button, so something I tried to do there was wrong.
I am still pretty new to IOS programmng, so there is a lot I still don't understand. I have the rest of
my app working pretty well now, but this last piece is giving me a headache. I am hoping someone here can
show me how to dismiss this view controller.
[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
sends a message to the parent view controller of your view controller. This is clearly not what you want. At best it would dismiss your view controller.
[self dismissViewControllerAnimated:YES completion:NULL];
is what you should do.
From -dismissViewControllerAnimated:completion:
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, it automatically forwards the message to the presenting view controller.
In this case your view controller (self) is the presenting view controller.

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!

How to get new view from clicking barbuttonitem?

I have made a barbuttonitem programmatically on a toolbar overlay. All of this appears when my camera is accessed. The button functions fine and the selector is fully capable of calling it.
Here's the overlay in .m , take a look at the doneButton selector.
- (UIView*)CommomOverlay {
//Both of the 428 values stretch the overlay bottom to top for overlay function. It
doesn't cover it.
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,420)];
UIImageView *FrameImg = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,420)];
[FrameImg setImage:[UIImage imageNamed:#"newGraphicOverlay.png"]];
FrameImg.userInteractionEnabled = YES;
UIToolbar *myToolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 428, 320, 50)];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self
action:#selector(doneButtonPressed)];
[myToolBar setItems:[NSArray arrayWithObjects: cancelButton, flexiSpace2, flexiSpace,
doneButton, nil] animated:YES];
[view addSubview:FrameImg];
[view addSubview:myToolBar];
return view;
}
Here's method I'm using for my void function.
//NewViewController is the nib I want to bring up when done is clicked.
-(void)doneButtonPressed {
NewViewController *UIView = [[NewViewController alloc] initWithNibName:nil bundle:nil];
UIView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:UIView animated:NO];
[UIView release];
NSLog(#"Acknowledged!");
}
The button is being called, but nothing happens. As you can see I added an NSLog function to see whether it was being called or not. "Acknowledged" shows up in the log when the button is clicked, so it's not a problem with the selector. The app doesn't crash when i use the button either, which should occur had I done some heavily faulty coding (in fact I don't even get any warnings about it), as far as Xcode is considered, everything is fine which, needless to say isn't.
I also have my .h files of NewViewController in place correctly in the view controller in which this code is being implemented.
UIView is the name of a class. Don't use it as the name of a variable. At best it is hugely confusing and is a probable reason for your problems. Rename UIView to something like myView everywhere in doneButtonPressed.

Resources