iPhone SDK 2: Programmatically adding an Info Button - iphone

I am trying to add an info button to my app to provide custom help.
Instead of adding the button to the nib and linking the event (touchUpInside) to the controller, I decided to add the button programmatically. The button shows up. When I add the target event handler to be executed when the button is touched, it does not work. That my method(doHelp) is not being called on touching the button.
When I debugged it, the event is not registered with the button! Although the code does not throw any exceptions.
Here is the code snippet FROM the view:
// Create a Button to get Help
UIButton *helpButton = [UIButton buttonWithType:UIButtonTypeInfoDark ] ;
buttonRect = helpButton.frame;
// CALCulate the bottom right corner
buttonRect.origin.x = rect.size.width - buttonRect.size.width - 8;
buttonRect.origin.y = rect.size.height - buttonRect.size.height - 8;
[helpButton setFrame:buttonRect];
[helpButton addTarget:self action:#selector(doHelp:) forControlEvents:UIControlEventTouchUpInside];
[helpButton setEnabled:TRUE];
[self addSubview:helpButton];
........
// Another METHOD ELSEWHERE in the VIEW object
-(void)doHelp:(id)Sender
{
[self setHelpNeeded:TRUE];
[self setNeedsDisplay];
}
What am I doing wrong please?
I have looked at the SDK help and samples and am really flummoxed!
Am hoping another pair of eyes will help! :-)
This code snippet is in the View Object in case you need to know.
I just added the doHelp to help the first 2 responders... thanks.
**UPDATE 6/4/09 ** -
I have been trying all night and nothing worked. I think there is something wrong in the way I have set up the method selector as my method never gets called. Everything else looks fine. Even using a NIB file does not work. I have tagged the button, retrieved it and added the method selector but to no avail. There is something fundamental which I am doing wrong... Argh!!!
Any ideas, anyone?

Resolved it finally!!! and learnt something in return. Did cost me a few days to figure this out.
The reason my UIButton object was not working was because I found that in case of a UIIMageView object:
"initWithImage: This method adjusts the frame of the receiver to match the size of the specified image. It also disables user interactions for the image view by default."
AND my UIButton had been assigned as a subview of a UIImageView control !!!
There was no errors / warnings. It just gets disabled quietly.
Solution: Created a container UIView object which now contains the UIImageView AND the button so that the button appears as overlayed on the Image but it is actually a sibling of the image and a subview of the dummy container UIView.

It's been awhile, but I think your addTarget needs to take the object that contains the doHelp: selector, like so:
[helpButton addTarget:self action:#selector(doHelp:)];
assuming somewhere in that same View you have:
- (void)doHelp: { }
passing nil to addTarget means that you're sending that selector to no recipient.

The problem is your addTarget:nil there. The selector you gave it for action is just a message it'll send to its target. You didn't give it a target, so it doesn't know what to do with that message. You probably want to pass in self instead of nil there.

I came across this while googling for a solution to the same problem. At least with the 3.x SDK, all you have to do is set the UserInteractionEnabled property of the UIImageView to YES.
Thanks for posting your discovery about the problem, I wouldn't have even thought to look at that one.

I had a similar problem where Buttons were outside of the view and did not receive tap messages
what helps is to set background colour of the parent view, to see that button is outside of it:
...
[buttonParentView addSubview: myButton];
buttonParentView.backgroundColor = [UIColor cyanColor];

Related

UIImageView's image not getting changed on postnotification in iPhone

In my app I have a UIImageView and at runtime once I download the image I am changing the image through postnotification but the image was not getting changed and I checked all my connections in nib and everywhere and it looks fine for me but still the image was not getting displayed can anyone help me in this regard. And my uiimageview was inside a scrollview and the scrollview was inside my main view
the following method was called on postnotification
- (void) refreshimages:(NSNotification *)notofication {
if ([[notofication name] isEqualToString:#"DownloadImgBinary"]) {
[activityview stopAnimating];
[activityview removeFromSuperview];
[self.view bringSubviewToFront:scrollView];
[self.scrollView bringSubviewToFront:imgCamera];
self.imgCamera.image = td.imgPhoto;
}
}
You need to check two things.
First, make sure that you are actually receiving the notification.
Put a breakpoint in the observer's target method, or stick an NSLog in there. If, when you do this, you see neither of them, then your notification isn't getting received.
Second, make sure that the image is actually getting downloaded.
Either use a web debugging proxy (I use Charles but it costs a bit, there are alternatives), or again, breakpoint somewhere. Or stick in a manual button somewhere that on-press tries to set the UIImageView's image, run the app, and press the button after you're sure the image downloaded.
Finally, to make sure something fishy isn't going on, stick two images in your project, give the imageView a default image (something glaringly obvious like checkerboard pattern), and then in the notification (assuming it is firing), set it to something else that is also glaringly obvious. Then test. This way you know that the bring-subview-to-front is working, and that your IB links are working.

Passing object data with UIButton press

I've created a custom UIView class FormDropdown, which contains a question & button in the nib. In the class is also an NSArray property which is supposed to store the various options for the button.
So a button can be placed by doing this, in for instance a viewDidLoad method:
FormDropdown *dropdown = [FormDropdown dropdownWithQuestion:#"This is an example question" andLabel:#"Select one" andOptions:[NSArray arrayWithObjects:#"One", #"Two", #"Three", nil]];
[self.view addSubview:dropdown];
Obviously, I'd like the button to, when tapped, bring up a UIPickerView with the options showing. But I'm stuck on how to send the options to any method. I know I can attach an action to the button like so:
[dropdown.dropdownButton addTarget:self action:#selector(dropdownPressed:) forControlEvents:UIControlEventTouchUpInside];
..but I can't see how I would pass the options from the dropdown.options array to the method?
I believe that you can do this by adding an "associative reference" from the UIButton to your object data.
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html
I am looking for a way to do that as well... however, it doesn't seem possible.
My possible solution: I think I am going to create a subclass of UIButton, and add a "NSObject *tagObject" property to it.
Anyone seems something wrong about it? (I am using ARC, and I am wondering if that would cause objects to remain in memory - I do not think so).

Problem showing some controls that are part of an UIView

In my app I have a custom UIView subclass (let's call it MyView) which contains three buttons and two labels. I add this view to a view controller which also has a table view (I add the instance of MyView at the bottom).
Because of the business logic rules, the labels and one button out of three are hidden in the beginning. So I do this in viewDidLoad:
self.myView.label1.hidden = YES;
self.myView.label2.hidden = YES;
self.myView.button1.hidden = YES;
which works fine. So these three are hidden and the remaining two buttons are visible.
Now this view controller is also a delegate for another class. At some point in time an event occurs in this other class which calls a notification method in my view controller.
In this notification method I have now to show the hidden controls. So I obviously tried the following:
self.myView.label1.hidden = NO;
self.myView.label2.hidden = NO;
self.myView.button1.hidden = NO;
but it doesn't work, they don't appear.
Any idea what I'm doing wrong? Do I need to somehow "repaint" self.myView after this so that the controls become visible? What am I missing here?
Many thanks in advance!
Edit
I have added some NSLogs after setting them visible and the logs show something like this:
label1.hidden = 0
label2.hidden = 0
button1.hidden = 0
So as per the logs, they should be visible.
Ok, so I solved the problem. I moved the code that sets the visibility of the controls in another method and I call this method like this:
[self performSelectorOnMainThread:#selector(updateControls) withObject:nil waitUntilDone:NO];
So what do you know, the notification method was called in another thread (I didn't know this, the library I am using is actually not mine and there's nothing in the docs about this fact).
Anyway, it's nice that it works now.
Thanks all!
Have you confirmed that your notification method is getting called? You shouldn't need to specifically refresh the view, but if you are sure that your method is called, then you can also try adding [self.myView setNeedsDisplay]; into your notification method.

iPhone UIButton buttonType always evaluates to 0?

Whenever I execute the code below I always get button type = 0 no matter what I specify for buttonWithType. Does anyone know an explanation for this behavior? I'm trying to distinguish button based on their type obviously without success since the buttonType property appears to be broken (or useless). As always thanks very much for any enlightenment you may provide!
UIButton *button = [[UIButton buttonWithType:UIButtonTypeDetailDisclosure] retain];
button.frame = frame;
NSLog(#"###################### LeftCalloutButtons - buttonWithTitle(73) - button type = %d",button.buttonType);
I encountered cases when UIButton properties (backgroundColor in my case) would have bogus value until the button is added to a view. Try querying the property once the button is on the screen.
EDIT: just saw another example of this behavior. This time it was about UISwitch.on. If I set it to YES right after alloc/init, it's not displayed as on. If I set it to YES in the viewDidLoad handler, it works as expected.
Apparently there's some lazy loading going on in the UIKit.
I have just verified the same issue with iOS 4.3.2 and Xcode 4.0.2. When looking at the internal structures of the UIButton instance in the debugger, the private struct _buttonFlags contains the unsigned int buttonType which is set to the correct value (non-zero in my case).
However, the debugger reports in response to print (int) [control buttonType] always 0.
In conclusion the method buttonType is broken and I will report this as a bug to Apple. I think it won't harm if other people who tried to use this method do the same.

Calling a method which is also used by UIButton?

I have a small iPhone app which I've created a button with some functionality in. My question is, how can I call this button without actually pressing it?
Any help would be appreciated!
Thanks
If you want to activate whatever target a button is wired to, you can call:
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
(TouchUpInside is the event you'd normally wire a button action to). This way if other targets are added or changed for any button (say for debugging) you don't have to alter your code.
This method is on UIControl which UIButton inherits from, which is why you might have overlooked it at first glance...
Have your button event call a function. You can also manually call the function yourself.
Example:
- (void) btnFunction {
NSLog (#"test");
}
...
UIButton *btn1 = [UIButton buttonWithType:UIButtonRoundedRect];
// other code to set up button goes here
[btn1 addTarget:self action:#selector(btnFunction) forControlEvents:UIControlEventTouchUpInside];
You can also call the function yourself:
[self btnFunction];
Your button shouldn't have functionality, it should just send a message to its target (or call a method, or call a function...).
You're free to send that message to that target yourself.
e.g. Your button's target outlet is connected to an IBAction on your controller. That IBAction is just a method of the form:
- (void) doSomething:(id)sender
In your own code do:
[controller doSomething:self];
It's exactly the same as having your button do it.