UIBarButtonItem created using initWithCustomView doesn't trigger action - iphone

I'm updating some old code, and to make more room in a toolbar, I'm converting the Buttons from test to images. An example of the new and old code in loadView is this:
// New code, doesn't work.
UIButton *toggleKeyboardBtn = [UIButton buttonWithType:UIButtonTypeCustom];
toggleKeyboardBtn.bounds = CGRectMake( 0, 0, showKeyboardImage.size.width, showKeyboardImage.size.height );
[toggleKeyboardBtn setImage:showKeyboardImage forState:UIControlStateNormal];
UIBarButtonItem *toggleKeyboardItem = [[UIBarButtonItem alloc] initWithCustomView:toggleKeyboardBtn];
[toggleKeyboardItem setTarget:self];
[toggleKeyboardItem setAction:#selector(toggleKeyboard:)];
// Original code, works jut fine.
UIBarButtonItem *setupItem = [[[UIBarButtonItem alloc] initWithTitle:#"Setup" style:UIBarButtonItemStyleBordered target:[UIApplication sharedApplication].delegate action:#selector(showSetupView:)] autorelease];
My new code is copied from Cannot set action on UIBarButtonItem, and I'm fairly certain that I'm not making their mistake since my text button is working just fine.
showSetupView() is in my AppController.m file, and the setup screen appears and disappears as the button is pressed.
toggleKeyboard(), OTOH, is in the same file as the loadView() routine, and currently consists of this code:
//- (void)toggleKeyboard {
- (IBAction)toggleKeyboard:(id)sender {
NSLog(#"Entering toggleKeyboard()...");
hiddenKeyboard = !hiddenKeyboard;
[self prepareToolbarsAndStatusbar];
}
Needless to say, although I see the button-press animation, I never see the NSLog message. And one last observation, made by accident. Changing the setAction selector to this:
[toggleKeyboardItem setAction:#selector(noSuchRoutine:)];
compiles cleanly, possibly indicating that my routine name is being ignored for some reason.
Anyone have any ideas? Thanks.

I found the answer! In button action not responding iphone, it's said that the action and target need to be set on the UIButton, not the UIBarButtonItem. I don't know if that's new with the latest version of Xcode, but I guess it is since other questions (such as the one I mention above) use a different technique. Here's my new code:
UIButton *toggleKeyboardButton = [UIButton buttonWithType:UIButtonTypeCustom];
toggleKeyboardButton.bounds = CGRectMake( 0, 0, keyboardAddImage.size.width, keyboardAddImage.size.height );
[toggleKeyboardButton setImage:keyboardAddImage forState:UIControlStateNormal];
[toggleKeyboardButton addTarget:self action:#selector(toggleKeyboard) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *toggleKeyboardItem = [[UIBarButtonItem alloc] initWithCustomView:toggleKeyboardButton];
//[toggleKeyboardItem setTarget:self];
//[toggleKeyboardItem setAction:#selector(toggleKeyboard:)];

Though its too late, but for future references, I would like to quote apple docs for the method,
- (instancetype)initWithCustomView:(UIView *)customView;
The bar button item created by this method does not call
the action method of its target in response to user interactions.
Instead, the bar button item expects the specified custom view to
handle any user interactions and provide an appropriate response.

Did you try
-(void)toggleKeyboard
and
[toggleKeyboardItem setAction:#selector(toggleKeyboard)]; without :
and it made any difference? Is the method declared in the interface file?

Related

Calling to function from UIBarButtonItem

I have button in my view with a setAction to a local function.
in GameOptions.m i have the next function:
- (void) changeSettings (UIBarButtonItem *) sender {
// do something
}
and a button that start it in GameOptions.m :
[btn1 addTarget:self action:#selector(changeSettings:) forControlEvents:UIControlEventTouchUpInside];
now i moved it from his view to a navigation controller as an rightBrButtonItem.
the myVC is an instance of small UIViewController with all the navigationBar settings,and each time i using pop ,push to it .
UIBarButtonItem *buttonNav1 = [[UIBarButtonItem alloc] initWithCustomView:settingsView];
[myVC.navigationItem setRightBarButtonItem:buttonNav1];
the problem is that this button is not in his GameOptions class and i want it to start the same function with implementation in GameOptions.m.
I would like to do the next thing :
buttonNav1 setAction:changeSettings;
but its impossible, the changeSetting is not recognized...
Tried : buttonNav1.action = self. but i'm not getting this function, only functions without parameters.
How can i call to chnageSettings from that button in navigationBar
All you need to do is inform your UIBarButtonItem of the existence of the GameOptions object.
That's what you were doing using self in :
[btn1 addTarget:self action:#selector(changeSettings:) forControlEvents:UIControlEventTouchUpInside];
Just after instanciating your UIBarButtonItem *buttonNav1, you can send it the message addTarget:action:forControlEvents: or, if you want to use setAction, don't forget to also use setTarget.
So now, your question is: what is the most elegant/efficient way to pass the GameOptions object's pointer to the UIBarButtonItem ;)

UISegmentedControl and adding targets

I'm sure this is an easy one for someone out there. I have a UISegmentedControl which I am using as a button (so as not to have to use the nasty default button) and I am having trouble getting the target to work....code as follows
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//read.buttonType = UIBarStyleBlackOpaque;
UISegmentedControl* read = [[[UISegmentedControl alloc] initWithFrame:CGRectMake(5, 50, 310, 54)] autorelease];
[read insertSegmentWithTitle:#"Read" atIndex:0 animated:NO];
read.tintColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.9 alpha:1];
read.segmentedControlStyle = UISegmentedControlStyleBar;
[read addTarget:self action:#selector(changeFilter:sender:) forControlEvents:UIControlEventTouchUpInside];
[read setTag:1];
[self.view addSubview:read];
}
and then
-(void)changeFilter:(id)sender{
}
for some reason, clicking on the UISegmentedControl does not fire the target method.
As an addendum, is there a simpler way to make nice looking UIButtons? I don't have access to Photoshop at work (although I do have gimp installed), so a way which doesn't involve image making would be good. I can't believe that apple didn't supply nice looking UIButtons in the UI, it seems such a fundamental thing to need?
Anyway, thanks for the help mis amigos.
thanks for the answers...I've tried the fix but it still doesn't fire
I now have
[read addTarget:self action:#selector(changeFilter:) forControlEvents:UIControlEventTouchUpInside];
then
#interface
-(void)changeFilter:(id)sender;
and
#implementation
-(void)changeFilter:(id)sender{}
Note that the method is in the same class as the UISegmentedControl. Maybe I should just try using the Glass button API which was suggested, but my boss hates me using third party libraries if there is a way of avoiding it!
The selector is wrong. It should be, action:#selector(changeFilter:), And change the event to forControlEvents:UIControlEventValueChanged, as UISegmentedControl doesn't send any actions for UIControlEventTouchUpInside event.
.h file u forgot to put this
-(void)changeFilter:(id)sender;
then
change this
[read addTarget:self action:#selector(changeFilter:sender:) forControlEvents:UIControlEventTouchUpInside];
To
[read addTarget:self action:#selector(changeFilter:) forControlEvents:UIControlEventValueChanged];
The action will automatically send the sender so just try #selector(changeFilter:).
As for your second question, ios5 will help you out there... but I can't say much about that yet. For now, you can use some uibutton classes that people have made to easily make some good looking buttons. Here's one:
http://hboon.com/glass-buttons-in-iphone-apps-without-using-image-files/

iPhone/iPad - issues with NavigationBar button?

I my application i have added button in NavigationBar like this..
UIBarButtonItem *more=[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"search-25by25.png"] style:UIBarButtonItemStylePlain target:self action:#selector(SelectMission:)];
self.navigationItem.rightBarButtonItem = more;
When i am clicking on button application get's shutdown...
If i am doing same thing with normal button it's working fine can any one help me why it's behaving like this?
Try This
UIImage *i=[UIImage
imageNamed:#"search-25by25.png"];
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
myButton.bounds = CGRectMake( 0, 0, i.size.width, i.size.height );
[myButton setImage:i forState:UIControlStateNormal];
[myButton addTarget:self action:#selector(SelectMission:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *more=[[UIBarButtonItem alloc] initWithCustomView:myButton];
self.navigationItem.rightBarButtonItem
= more;
hope it helps :)
Have you looked in the code for SelectMission:? The code you've posted is only for presenting the button, which from your description appears to be working.
Also if there's anything being dumped into the console (Command-Shift-R)?
Judging by the crash log in your comment, I would say this has nothing to do with the UIBarButtonItem class in particular, and everything to do with your action handler. The crash logs tell the whole story: Your class does not implement a method called SelectMission: that takes one argument. Some caveats about the #selector keyword that you will want to double check:
1) Capitalization. Make sure that the method you implement is SelectMission:. Not selectMission:, selectmission:, Selectmission:, etc.
2) Arguments. The colon indicates that the method SelectMission: takes one argument. If you have implemented it and forgotten the argument it will crash with the exception you posted.
That should help narrow down the issue.

iphone navigation & saving data to plist

I'm creating a small iPhone app, when application lauches, it will ask the user to sign up or Login. If they choose sign up safari will open. This part is done.
////button code
button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
button.frame = CGRectMake(10, 150, 300, 50);
[button setTitle:#"Login" forState:UIControlStateNormal];
button.backgroundColor = [UIColor clearColor];
[button addTarget:self action:#selector(myaction:) forControlEvents:UIControlEventTouchUpInside];
button.adjustsImageWhenHighlighted = YES;
[mainView addSubview:button];
[button release];
If they click Login -
How to navigate to next window asking for username / password ? Can I do it button action ?
2.How I will store their info in plist ( if i'm correct ) ?
Thanks in advance.
One way to do (1.) is:
define a LoginViewController class that inherits from UIViewController
create a nib file named "login" with the UI elements for your login view
make your login button action do somehting like:
LoginViewController *controller = [[LoginViewController alloc] initWithNibName:#"login" bundle:nil];
[self presentModalViewController:controller animated:NO];
There are really several different questions here disguised as one.
1: in the method -buttonAction is where your navigation logic will be. It looks like you're probably working from xibs out of Interface Builder
2: You'll need to use the NSDictionary method called -writeToFile:atomically:. The arguments are the path string for the file to be stored on flash memory, and a BOOL YES/NO value that determines if the file is written immediately, or if it checks for errors first. I'd recommend setting atomically: to YES.
I'm gathering from your question that you're not familiar with Cocoa and UIKit. You'll be hard pressed to get a tutorial on how to put your application together. You're going to need to try Google for swapping views and handling page navigation. It's a lot deeper than what I'm describing here.

How can I safely memory manage a button that I want to remove from the UI?

I'm making an app that is kinda like iBooks. There is some stuff on the screen, each item represented by a small thumbnail. I want the user to be able to delete the items much like when you tap the "Edit" button in iBooks - an X comes up, and the item is deleted. I'm using the delegation pattern to handle all of this, so here is some code:
// Button is created in CustomView.h class
UIImage *deleteImage = [UIImage imageNamed:#"delete.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
self.deleteButton = button;
[self.deleteButton setImage:deleteImage forState:UIControlStateNormal];
[self.deleteButton addTarget:self action:#selector(deleteIt) forControlEvents:UIControlEventTouchUpInside];
// Here's what's called when the delete button is pushed
- (IBAction)deleteMap {
[self.customViewDelegate itemWasDeleted:self];
}
// And here's the implementation of that method, in a View Controller
- (void)itemWasDeleted:self:(CustomView*)customView {
// delete domain object
// . . .
[self.collectionOfCustomViews removeObject:customView];
[customView removeFromSuperview];
}
The problem with this code is that I get a Bad Access Exception. Via NSZombie, looks like this:
* -[UIButton _unhighlight]: message sent to deallocated instance 0x5f4a740
I guess what's happening is that when my target-action implementation is called, it's not yet safe to release the button, as I'm doing in my delegate method. So my question is, what's a better approach to doing this so that may app doesn't crash? I'd like to know the cleanest approach possible.
If collectionOfCustomViews was the only object retaining customView then you released it when you removed it, so it can't respond to removeFromSuperview.