Why doesn't this work? I want the closeBtn in the new view controller to call a method called dismiss: in the current view controller.
NewViewController *newVC = [[NewViewController alloc] initWithNibName:#"NewViewController" bundle:[NSBundle mainBundle]];
[newVC.closeBtn addTarget:self action:#selector(dismiss:) forControlEvents:UIControlEventTouchUpInside];
The dismiss: method is never called in the current view controller. closeBtn is correctly set up as a property in NewViewController and linked in the .xib file.
Create the object of the another controller and specify it in addTarget. Give the name of the method in the action parameter.
i.e anotherController *obj;
[button addTarget:obj action:#selector(MethodName) forControlEvents:UIControlEventTouchDown];
Generally, that is not a good way to deal with methods and UI elements.
However, you can do something like this, though it is ugly.
[yourButton addTarget:self action:#selector(yourButtonPressed:) forControlEvent:UITouchUpInside];
- (void) yourButtonPressed:(id)sender {
OtherVC* otherVC = [OtherVC alloc] initWithNibName#"NewViewController"] ...
[otherVC theDesiredMethod];
[otherVC release];
}
This works but is not really good you are probably better off moving the function into the proper VC.
Hope that helps.
Related
The issue I am having is that I want to call a method in a navigationController by clicking a button inside a UIView (footer). When I press the button, it should call the method I'm trying to access to open the Video recorder in the code below.
I was told I could implement a delegate method or use a NSNotification. Below is what I have:
My footer (ESPhotoDetailsFooterView.m) has my button that I created. My footer only contains a UIView.
The method I'm trying to access in my footer resides in (ESTabBarController.m)
This is what I am trying to trigger when pressing my button:
RecorderViewController *viewController = [[RecorderViewController alloc] init];
[viewController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self.navController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self.navController pushViewController:viewController animated:NO];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:self.navController animated:YES completion:nil];
});
I am new to Objective C and understand the basics. I cannot figure out what I need to do to accomplish this. Any help would be much appreciated.
The code for the button is as follows:
// Create a standard UIButton programmatically using convenience method
UIButton *camButton = [UIButton buttonWithType:UIButtonTypeCustom];
// Set the location (x,y) and size (width,height) of the button
camButton.frame = CGRectMake(9.0f, 8.0f, 35.0f, 35.0f);
// Create UIImages from image resources in your application bundle
// using convenience methods (no need to release)
UIImage *normal = [UIImage imageNamed:#"BingComm"];
UIImage *highlighted = [UIImage imageNamed:#"BingCommClick"];
// Set the button's background to an image
[camButton setBackgroundImage:normal forState:UIControlStateNormal];
[camButton setBackgroundImage:highlighted forState:UIControlStateHighlighted];
// Add the target-action for the touch event
#pragma GCC diagnostic ignored "-Wundeclared-selector"
[camButton addTarget:self action:#selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.mainView addSubview:camButton];
Yes, in this case delegation is a good choice, basically you will need a delegate object in your footer view. Then you set the delegate to TabBarController at runtime.
When user clicks the button, call you delegate with your method [delegate method]
This is a very important design pattern objective-c, it would be very helpful if you can follow this tutorial to fully understand delegation.
http://www.alexefish.com/post/522641eb31fa2a0015000002
I agree that delegation is important and very much worth learning, but another way to solve the same problem would be to the following:
In your method definition for btnClicked, call the following code
if([self tabBarController]) {
[[self tabBarController] methodToCall];
}
Since your view controller should be embedded within a tab bar controller, it will have this property set. You can then call any public methods contained within the tabBarController class.
I have created a button in a UIView subclass . I need to call popViewControllerAnimated via this button , but nothing work ! and I cannot see the viewController push back to rootViewController . here is my code :
- (void)SomeFunction {
backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton showsTouchWhenHighlighted];
[backButton addTarget:self
action:#selector(backToMainMenu)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)backToMainMenu {
[self.window.rootViewController.navigationController popViewControllerAnimated:YES];
NSLog(#"back");
}
I change the code to this :
UINavigationController *vc = self.window.rootViewController.navigationController;
[vc.navigationController popViewControllerAnimated:YES];
but nothing happens .
I think you need to use the proper target format which takes the button as an argument. So add target function like this:
[backButton addTarget:self
action:#selector(backToMainMenu:)
forControlEvents:UIControlEventTouchUpInside];
and the target should look like this:
- (void) backToMainMenu:(UIButton *) sender{
[self.navigationController popViewControllerAnimated:YES];
}
A better option is to use Delegate pattern because in your current logic you are breaking the MVC architecture and guidelines.
Create a Protocol in your subview class. The receiver of this delegate would be the view controller class from which you are showing your view. In event handling of the button, call the delegate method and from the view controller you would be able to call popViewControllerAnimated successfully.
I believe your fundamental problem (besides design) is in (void)backToMainMenu ... self.window.rootViewController.navigationController will be nil, so this method does nothing
from UIViewController class reference:
If the receiver or one of its ancestors is a child of a navigation controller, this property contains the owning navigation controller. This property is nil if the view controller is not embedded inside a navigation controller.
so you see, the rootViewController cannot be embedded inside a nav controller can it, it is the bottommost one..
why don't you test this:
{
UINavigationController *vc = self.window.rootViewController.navigationController;
if (vc==nil){
NSLog(#"nav controller is nil, this will never work");
}
[vc.navigationController popViewControllerAnimated:YES];
}
I also fully agree with #rory's answer there about design..
PS did you actually create a UINavigationController in order to push this viewController?
I have a UIView that has some buttons that I need to add actions to.
I've tried the this:
HeaderViewController * header = [[HeaderViewController alloc]initWithNibName:#"HeaderViewController" bundle:[NSBundle mainBundle]];
[header.aboutUs addTarget:self action:#selector(aboutUsPage:) forControlEvents:UIControlEventTouchUpInside];
[header.MyLibrary addTarget:self action:#selector(myLibraryPage:) forControlEvents:UIControlEventTouchUpInside];
[self.tableView addParallaxWithView:header.view andHeight:229];
But the button is not responding at all.
What have I done wrong.
Here's the thing, You are creating the view controller and then setting targets and actions for buttons that are referenced as the view controller's property.
I suspect that if you log or put a breakpoint just before you set the target and actions and then step through, the buttons will be nil.
View controllers load their views lazily. So although you have created the view controller, you haven't asked it to load it's view. So the buttons have not been created from the nib. So the properties are nil, and not target action is getting set.
The first option to fixing it is to move the last line so it looks like this:
[self.tableView addParallaxWithView:header.view andHeight:229];
[header.aboutUs addTarget:self action:#selector(aboutUsPage:) forControlEvents:UIControlEventTouchUpInside];
[header.MyLibrary addTarget:self action:#selector(myLibraryPage:) forControlEvents:UIControlEventTouchUpInside];
That way you are calling the view, which will initialise it, and the button parameters should not be nil after this.
The classier way of doing this sort of thing is to define a protocol for responding to clicks on the button, and make the calling view controller a delegate that implements the protocol methods. That way you only have to set the delegate when you create the object, and you don't have to configure the buttons each time.
If you write :
[header.aboutUs setTarget:self];
AND if your class (I mean here self) implements the function aboutUsPage:, it should work.
I have a UITabBarController bassed app. I'm instantiating it from the app delegate and adding a custom button in the tab bar controller. when that button is clicked, I want to present another view modally, but I cant seem to figure out how to do it. to add the button I'm basically doing this
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
[self.tabBarController.view addSubview:button];
[button addTarget:self action:#selector(showModalViewController:) forControlEvents:UIControlEventTouchUpInside];
and also in the app delegate I have a method
- (void) showModalViewController {
DummyViewController *addController = [[DummyViewController alloc]
initWithNibName:#"DummyViewController" bundle:nil];
//addController.delegate = self;
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:0];
// Create the navigation controller and present it modally.
[self.tabBarController.selectedViewController presentModalViewController:addController animated:YES];
// The navigation controller is now owned by the current view controller
}
I keep getting unrecognized seletor
Your selector looks for a method named showModalViewController: but your actual method is named showModalViewController. Change one or the other.
Either change the selector to #selector(showModalViewController) to match the existing method, or change the method to:
- (void)showModalViewController:(UIButton *)button {
Don't change both.
my iOS application use storyboard
it have 2 view controllers:
- main storyboard view controller
- and popover view controller with some objects in it
i've got a button on main view controller and it creates programing every time i run the application:
*CGRect buttonFrame = CGRectMake(10., 10., 120., 50.);
oneButton = [UIButton buttonWithType:UIButtonTypeCustom];
[oneButton setImage:[UIImage imageNamed:[NSString stringWithFormat:#"someImage.png", img]] forState:UIControlStateNormal];
[oneButton setTag:img];
[oneButton setFrame:buttonFrame];
[oneButton addTarget:self action:#selector(pressButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:oneButton];*
the action of this button show my popover view like that:
*- (void) pressButton:(id)sender {
popoverViewController *popoverFrame = [self.storyboard instantiateViewControllerWithIdentifier:#"myPopoverView"];
popoverWithObjects = [[UIPopoverController alloc] initWithContentViewController:popoverFrame];
[popoverWithObjects presentPopoverFromRect:[sender frame] inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
}*
from now the situation is, that i can't send to my button any message or result.
i want to say to my program button (note - i've got only sender of this button action:#selector(pressButton:) ) that popover return some result or some action of an object in popover send anything (string for example)
Or in another words when i interact with any object like button on popover view, i want to change parent buttons title label
Use NSNotificationCenter.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html
You need to use delegate. Check out my answer to this similar question from this SO.
Edit: Link to tutorial on Storyboard and delegate pattern usage. And my original answer to delegate on this SO
How about writing a function on your Main View Controller to do what you want. Then call that function from the popover? (i.e. use 'prepare for segue' to send the popover the id of the Main View Controller, and then use that id to call the function on Main View from the popover)