April 21, 2010

iPhone: Subviews in UIButtons block the touch, unless...

If you add a UIView or other UIView subclass to a UIButton, the UIView object will block touches/clicks on the UIButton. There's a simple fix to ensure that subviews in your UIButton don't interfere. In the following case, I have a subclass of UIView that loads an image from the web (WebImage), that's created inside a subclass of UIButton:
WebImage *thumb = [[WebImage alloc] initWithFrame:CGRectMake(1, 1, 94, 94) andImageUrl:@"http://mysite.com/thumbnail.png"];
[self addSubview:thumb];
thumb.userInteractionEnabled = NO;
thumb.exclusiveTouch = NO;
[thumb release]; 
All you need to do is set userInteractionEnabled and exclusiveTouch to NO or FALSE, and the subview will no longer block your button.

April 19, 2010

iPhone: You can't have a UIView subclass named "WebView"

Good lord, this wasted half a day. I was creating a UIView subclass to hold a UIWebView, and named it "WebView". Not too abstract, right? I kept getting the following cryptic error:
*** -[WebView _isAncestorOfFirstResponder]: unrecognized selector sent to instance 0x463a7b0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[WebView _isAncestorOfFirstResponder]: unrecognized selector sent to instance 0x463a7b0'
I renamed my class "WebViewView" and no more errors. Thanks for the shitty error messages Apple!

April 14, 2010

iPhone/iTouch/iPad: Check for the ability to make a phone call

I came across a situation where I wanted to lay out different buttons in case the iDevice (iPod Touch or iPad) can run my app, but can't make a phone call. The iPhone will display a "Call Store" button, but other devices won't. For a simple check, look at the following code, which checks for the device name, and looks for "iPhone" at the beginning of the string. It's a very simple implementation, but I didn't need further detection functionality for this project.
// check iDevice model for calling capability and initially assume it's an iPhone
NSString *model= [[UIDevice currentDevice] model];
BOOL canMakeCalls = YES;
//model = @"iTouch"; // manual test for non-iPhones in simulator
if ( ![model hasPrefix:@"iPhone"] ) canMakeCalls = NO;
[model release];
Then you can conditionally display or disable UI elements depending on whether it's for the iPhone only. This can obviously be customized further and more robustly, but for something quick and easy, I hope you find it useful. Check out this blog for a much more detailed detection class.