iOS Objective-C UIBarButtonItem Action Not Called - ios

I have a property:
#property (strong, nonatomic) IBOutlet UIBarButtonItem *backButton;
It gets set like this:
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay target:self action:#selector(goBack:)];
backItem.imageInsets = UIEdgeInsetsZero;
UIToolbar *backToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
backToolbar.userInteractionEnabled = YES;
[backToolbar setTransform:CGAffineTransformMakeScale(-1, 1)];
backToolbar.items = [NSArray arrayWithObjects:backItem, nil];
backToolbar.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
backToolbar.clipsToBounds = YES;
self.backButton = [[UIBarButtonItem alloc] initWithCustomView:backToolbar];
self.backButton.enabled = YES;
self.backButton.imageInsets = UIEdgeInsetsZero;
Which I would have thought would set the selector to this:
- (IBAction)goBack:(id)sender {
NSLog(#"goBack pushed");
[self.iframeView goBack];
}
But goBack pushed is never logged out when I click the button, though the iframeView (just a UIWebView) does go to the previous page.
I've also tried setting the action like this (set right below the above code):
[self.backButton setTarget:self];
[self.backButton setAction:#selector(goBack:)];
Any ideas how I can adjust the code such that the selector is called when I push the back button?

Did you create your backButton from storyboard (because you declare it as an IBOutlet)?
If you already create it from storyboard then you can simply Ctrl-Left Click to drag the button into your implementation file .m where the - (IBAction)goBack:(id)sender is to create the selector.
UPDATE:
I just noticed you said this
But goBack pushed is never logged out when I click the button, though
the iframeView (just a UIWebView) does go to the previous page.
UIWebView has the goBack function already. So by setting
[self.backButton setAction:#selector(goBack:)];
When the button is pressed it will called the goBack function of the UIWebView.
All you have to is give it a different name:
[self.backButton setAction:#selector(backButtonPressed:)];
- (IBAction)backButtonPressed:(id)sender{
NSLog(#"goBack pushed");
[self.iframeView goBack];
}

I tried your code and I found a line of code is missing which is why the selector goBack: is not triggered. If I am not wrong the button "Play" is not visible when you compile
self.navigationItem.rightBarButtonItem = self.backButton;
As I observed you have created the bar button, toolbar programmatically, also you don't need the #property (strong, nonatomic) IBOutlet UIBarButtonItem *backButton; if your not using it else where in the code or you have to omit the IBOutlet.
Hope these helps.

Related

How show popup menu list when clicking on UITextField iOS? (Kxmenu)

Sorry I am a little bit new on iOS Development , for a project i need to use popup list menu library ( i know iOS support PickerView , ... for the purpose of choosing from a list menu) but i need to use that popup list , so after some search i find this library :
https://github.com/kolyvan/kxmenu
Which i have seen the example on that project. I added same as kxmenu Example to my project and it works , but I need a slight change. Instead of clicking on Button (in the example) to open the popup menu , i want whenever user click inside UITextField , would open the popup menu.
The buttons are added as subview by this example , but i need to connect an action to the UITextField which is not written programatically (it's not added by adding subview...)
here is the code (of Example) that I really Appreciate if someone tell me what changes do i need to apply to the following code , to make this changes:
instead of using the button , Use UITextfield , I mean when user click on The UITextField it would open the kxmenu popup
please consider that in the kxmenu example , Button are added programatically , but the UITextField that i have is a property.
here is the part of the source code:
//#part 1 {
_btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
_btn1.frame = CGRectMake(5, 5, 100, 50);
[_btn1 setTitle:#"click Me" forState:UIControlStateNormal];
[_btn1 addTarget:self action:#selector(showMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btn1];
//#part 1 }
- (void) pushMenuItem:(id)sender
{
NSLog(#"%#", sender);
}
//#part 2 {
- (void)showMenu:(UIButton *)sender
//#part 2 }
{
NSArray *menuItems =
#[
[KxMenuItem menuItem:#"ACTION MENU 1234456"
image:nil
target:nil
action:NULL],
[KxMenuItem menuItem:#"Reload page"
image:[UIImage imageNamed:#"reload"]
target:self
action:#selector(pushMenuItem:)],
[KxMenuItem menuItem:#"Search"
image:[UIImage imageNamed:#"search_icon"]
target:self
action:#selector(pushMenuItem:)],
];
KxMenuItem *first = menuItems[0];
first.foreColor = [UIColor colorWithRed:47/255.0f green:112/255.0f blue:225/255.0f alpha:1.0];
first.alignment = NSTextAlignmentCenter;
[KxMenu showMenuInView:self.view
fromRect:sender.frame
menuItems:menuItems];
}
With My Slight iOS Knowledge i think these changes might apply (but i have tried that and it won't work with UITextField
instead of //#part 1 shwon in above code , i need to replace it with :
[currentTextField addTarget:self action:#selector(showMenu:) forControlEvents:UIControlEventTouchUpInside];
instead of UIButton as declaration of argument of sender in //#part 2 shwon in above code , i need to change it UITextField as argument of sender.
I would appreciate if someone show me by writing some code what changes do i need to apply to above source code for the following purposes. Thanks!
you can use "UITextFieldDelegate", for example:
- ( BOOL )textFieldShouldBeginEditing:( UITextField *)textField
[self taggle];
)
-(void)taggle{
NSArray *menuItems =
#[
[KxMenuItem menuItem:#"开启闪光灯"
image:nil
target:self
action:#selector(clickTorch)],
[KxMenuItem menuItem:#"翻转"
image:nil
target:self
action:#selector(clickCamera)],
[KxMenuItem menuItem:#"美颜"
image:nil
target:self
action:#selector(clickBeautyFace)],
];
[KxMenu showMenuInView:self.view
fromRect:textField.frame // UITextField *textField = [[UITextField alloc] initWithFrame:....] // you can write any frame and change it.
menuItems:menuItems];
}

Should [UIView endEditing:YES] ever return no?

I am having a hell of a time fixing a bug, which currently is only occurring when I run my app on the simulator. Essentially, I have a UITextView that I am trying to send the message endEditing to. If I send the message while the user is editing the textview (forced or otherwise) I get back YES. If however, the user has not yet begun editing the textview and I send the message endEditing:YES, I get back NO. Should this even be possible? Shouldn't endEditing:YES always force the view to end editing?
Additional Details: I have tried setting the owning class to be the uitextviews delegate, but even then it doesn't look like the shouldEndEditing method even gets called.
UPDATE: It does not seem that this is normal behavior (that the method should return no if the text field is not currently the first responder).
I created a simple test:
AppDelegate.h
#import <UIKit/UIKit.h>
#interface DRAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (assign) IBOutlet UITextView *textView;
#property (assign) IBOutlet UIButton *endButton;
#property (assign) IBOutlet UILabel *results;
-(IBAction)tapEndEditingButton:(id)sender;
#end
and AppDelegate.m
-(void)tapEndEditingButton:(id)sender
{
BOOL didEndEditing = [self.window endEditing:YES];
NSString *result = (didEndEditing) ? #"YES" : #"NO";
_results.text = result;
}
Regardless of whether the textfield has focus, and regardless of whether I set the force parameter of endEditing to YES or NO, didEndEditing gets set to YES.
Check Apple Doc on UIView
endEditing:
Causes the view (or one of its embedded text fields) to resign the first responder status.
...
Return Value
YES if the view resigned the first responder status or NO if it did
not.
Discussion
This method looks at the current view and its subview hierarchy for
the text field that is currently the first responder. If it finds one,
it asks that text field to resign as first responder. If the force
parameter is set to YES, the text field is never even asked; it is
forced to resign.
So... When you said:
If however, the user has not yet begun editing the textview and I send the message endEditing:YES, I get back NO
It's perfectly fine because in your scenario, since there is no firstResponder to resign, calling -endEditing: will return NO and doesn't harm the performance (isn't a bug either, imho)
To answer the essence of the question:
[UIView endEditing:YES/NO]; will return NO if the specified UIView object was not the firstResponder.
Example:
-(void)testEndEditing
{
UIButton *btnTest = [UIButton buttonWithType:UIButtonTypeCustom];
[btnTest setFrame:CGRectMake(0, 130, 320, 44)];
[btnTest setBackgroundColor:[UIColor blueColor]];
[btnTest addTarget:self action:#selector(myEndEditing:)
forControlEvents:UIControlEventTouchUpInside];
[btnTest setTitle:#"End Editing" forState:UIControlStateNormal];
[self.view addSubview:btnTest];
UITextField *txtFTest = [[UITextField alloc] init];
[txtFTest setFrame:CGRectMake(0, 50, 320, 30)];
[txtFTest setBackgroundColor:[UIColor orangeColor]];
[txtFTest setText:#"textField"];
[self.view addSubview:txtFTest];
/*
globally declare "UITextView *txtVTest;"
*/
txtVTest = [[UITextView alloc] init];
[txtVTest setFrame:CGRectMake(0, 80, 320, 50)];
[txtVTest setBackgroundColor:[UIColor redColor]];
[txtVTest setText:#"textView"];
[self.view addSubview:txtVTest];
//make UITextField object the firstResponder
[txtFTest becomeFirstResponder];
}
-(void)myEndEditing:(UIButton *)sender
{
//test endEditing method on UITextView object
BOOL isWhat = [txtVTest endEditing:YES];
NSLog(#"%i",isWhat);
}
PS: If neither the textField nor the textView is the firstResponder then it returns YES (dunno why but i'll check)

showing a UITextField that is a local variable vs a property in a custom view

I am mocking up a quick demo of a project but am having a problem with a UITextField.
The behavior that we want is that when a user clicks on a button, there should be a custom view that appears with a UITextField and a UIButton in a custom view that overlays the main view.
I have a custom view called Searchview and the following in the Searchview.m. The problem is that when the textField is a property, it doesn't show but when it is a local variable, it does show. Can anybody help me with what is going on so that the UITextField shows? Is how I am doing this even the right idea (custom UIView or custom UIControl or a modal controller)? Finally, would setNeedsDisplay be appropriate here?
thx in advance
#interface Searchview()
#property (nonatomic, weak) UITextField *textField;
#end
- (void)drawRect:(CGRect)rect
{
// this doesn't work
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 120.0f, 25.0f)];
self.textField.returnKeyType = UIReturnKeyDone;
self.textField.placeholder = #"Writer";
self.textField.borderStyle=UITextBorderStyleBezel;
[self.textField addTarget:self
action:#selector(textFieldDone:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[self addSubview: self.textField];
/* this works
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0f, 10.0f, 120, 25)];
textField.returnKeyType = UIReturnKeyDone;
textField.placeholder = #"Writer";
textField.borderStyle=UITextBorderStyleBezel;
[textField addTarget:self
action:#selector(textFieldDone:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[self addSubview: textField];
*/
UIButton *mButton=[UIButton buttonWithType:UIButtonTypeRoundedRect];
mButton.frame=CGRectMake(200.0f,10.0f,100.0f,37.0f);
[mButton setTitle:#"search" forState:UIControlStateNormal];
[mButton addTarget:self action:#selector(showSearchController:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:mButton];
[self setNeedsDisplay];
}
As a property - not showing:
As a local variable - showing:
#property (nonatomic, strong) UITextField *textField;
change the weak to strong and change the self.textFiled to _textField to have a try
And make sure your textField property not be released
It's pretty simple when you think about it. ARC (approximately) converts the following code:
self.weakProp = [[Foo alloc] init];
to the equivalent of the following "manually reference-counted" code:
Foo * temp = [[Foo alloc] init];
self.weakProp = temp;
[temp release];
Nothing is retaining it, so it is released.
I can only think of two reasons to have assign/weak IBOutlets:
For an outlet in a VC, so it doesn't retain a subview when its view is set to nil (e.g. on a memory warning). This is less relevant in iOS 6.0 since views are not automatically released on a memory warning (so if you do it, you can release them all explicitly).
For a view where the outlet points to a superview (and would cause a retain cycle). This is quite rare.
In general, I prefer strong IBOutlets: They might keep objects alive for a little longer than necessary, but they are safer than assign and more efficient than weak. Just watch out for retain cycles!

Strange behaviour of dynamically added UIBarButtonItem

I'm working on an application in which I'm adding UIBarButtonItem to UIToolbar dynamically. When User clicks on a bar button. I'm changing it's tint color to red.
But for some bar buttons it's not working and the application is crashing.
Here is my code:
#interface myClass : UIViewController
#property (nonatomic, retain) NSMutableArray *barButtonItems;
#property (nonatomic, retain) IBOutlet UIToolbar *toolBar;
#end
#implementation myClass
#sythesize barButtonItems, toolBar;
- (void)viewDidLoad
{
[super viewDidLoad];
barButtonItems = [[NSMutableArray alloc] init];
[self initToolBar];
}
//To set the tool bar
- (void)initToolBar
{
[self addBarItem:#"PlantDetails" actionName:#"createPlantDetails:"];
[self addBarItem:#"ElectricalEquipmentInventory" actionName:#"createInventory:button:"];
toolBar.items = barButtonItems;
}
//Create bar button item
- (void)addBarItem:(NSString*)barButtonName actionName:(NSString*)methodName
{
UIBarButtonItem *plantDetails = [[UIBarButtonItem alloc] initWithTitle:barButtonName style:UIBarButtonItemStyleDone target:self action:NSSelectorFromString(methodName)];
[barButtonItems addObject:plantDetails];
[plantDetails release];
plantDetails = nil;
}
//Changes the barbutton tintcolor when user selected
-(void)changeSelection:(UIBarButtonItem *)button
{
NSArray *tempArray = toolBar.items;
for(int loop = 0; loop<[tempArray count]; loop++)
[[tempArray objectAtIndex:loop] setTintColor:[UIColor blackColor]];
[button setTintColor:[UIColor redColor]];
}
//First bar button method
- (void)createPlantDetails:(UIBarButtonItem *)button
{
[self changeSelection:button];
NSLog(#"createPlantDetails");
}
//second bar button method
- (void)createInventory:(int)selectedIndex button:(UIBarButtonItem *)button
{
[self changeSelection:button];
NSLog(#"createInventory");
}
#end
Here my issue is the bar button with only one parameter in it's selector is working perfectly (createPlantDetails) but when I click on the bar button which have two parameter in it's selector (createInventory) the application is crashing on [button setTintColor:[UIColor redColor]]; of changeSelection method.
Crash log is something like: touches event have no method like setTintColor .
I searched a lot but couldn't find a solution. Please help me.
Thanks in advance
The method for the action property has to have one of the following three forms:
- (void)methodName;
- (void)methodName:(id)sender;
- (void)methodName:(id)sender withEvent:(UIEvent *)event;
You can't use any arbitrary format or custom parameters (the button wouldn't know what to pass for them).
The createPlantDetails: method works because it matches the second form.
The createInventory:button: method fails because it doesn't match any of the expected signatures.
Since your method has two parameters, when the button calls the method, the button passes a UIEvent object in the second parameter which in your method is named button.
In changeSelection:, it crashes when it tries to call setTintColor: because button is really a UIEvent and not the UIBarButtonItem (ie. the sender).

What's the correct way to create and show an UIBarButtonItem programmatically?

I'm having a problem: the app I'm working on crashes every time an UIBarButtonItem is tapped.
I'm creating the button in the viewDidLoad method of my main ViewController:
UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithTitle:#"Settings" style:UIBarButtonItemStyleBordered target:self action:#selector(showSettings)];
self.navigationItem.leftBarButtonItem = settingsButton;
The showSettings method only contains an NSLog():
- (void)showSettings {
NSLog(#"ciao");
}
The button is correctly showed in the navigation bar, but whenever is tapped the application crashes with an exc_bad_access message.
What am I doing wrong?
EDIT: ARC is ebabled and I'm running the code in the iOS 5.1 simulator.
Changes:
UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithTitle:#"Settings" style:UIBarButtonItemStyleBordered target:self action:#selector(showSettings:)];
- (void) showSettings:(UIBarButtonItem *)sender
{
}
As mentioned by the ref doc about selector:
If an object receives a message to perform a method that isn’t in its
repertoire, an error results. It’s the same sort of error as calling a
nonexistent function. But because messaging occurs at runtime, the
error often isn’t evident until the program executes.
So make sure your method is in the scope of your viewcontroller. I will start by checking you don't have any typo. If your method don't take any argument don't use : and make sure you have declared your method in your class description.
To create a uibarbutton programatically. this example is for custom uibarbutton
UIButton *timebutton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 90, 40) ];
[timebutton setTitle:timeString forState:UIControlStateNormal];
[timebutton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
UIBarButtonItem *rightBarButtonItem1 = [[UIBarButtonItem alloc]
initWithCustomView:timebutton];
[rightBarButtonItem1 setTintColor:[UIColor blackColor]];
//set the action for button
rightBarButtonItem1.action = #selector(navigationMethod:);
self.navigationItem.rightBarButtonItem = rightBarButtonItem1;
//Method declaration
-(IBAction)navigationMethod:(id)sender{
// action
}
Hope this helps you

Resources