Targetting iPhone 3gs and superior

I recently had a problem with one of the apps i’m working on. (Yeah, yet another problem!). The first release supported ARMv6 (which is handy when targetting older devices, as well, such as 1st and 2nd iPod generations, and the old iPhone 3g).

As it turns out, you cannot change the requirements of an app after pushing an update. I mean, you cannot simply remove ‘ARMv6’ support. Apple’s policy is that … you should continue supporting all of the target platforms you’ve enabled in the very first release.

So far so good. But what happens if you need to link a library which is built for ARMv7, without ARMv6 support?. Two options… one… weak linking. The second, would be to simply deprecate ARMv6. But apple… doesn’t want this.

Hey… wait… there is a catch to it!!. If you update the ‘target iOS platform’ to iOS 4.3 (or higher)… you can safely drop ARMv6 architecture.

Why?. iOS 4.3 cannot be installed on older devices, such as the iPhone 3g. It doesn’t support ARMv6 architecture.

So… long short story… the only way to safely drop armv6 support is by setting an upper target platform (4.3+).

Who’s using anything older than that???. Go on… deprecate those old devices!. They have already fulfilled their cycle…

 

GPS in Safari Mobile

So… what if you wanna get the GPS position, but within a WebApp’s context?. There are several tools, such as PhoneGap, that encapsulate GPS access. But it turns out that there is an extremely easy way to accomplish this task.

Check out this JavaScript snippet… easy, right?

[cc lang=”objc”]navigator.geolocation.getCurrentPosition(foundLocation, noLocation);

function foundLocation(position)
{
var lat = position.coords.latitude;
var long = position.coords.longitude;
alert(‘Found location: ‘ + lat + ‘, ‘ + long);
}

function noLocation()
{
alert(‘Could not find location’);
}
[/cc]

Debugging BAD_ACCESS crashes

Newbies can rely on ARC to handle memory management. But personally, i’d rather handling everything myself. Old school!.

Besides that, you’ll probably need to support iOS 4 devices, as well. So… at least for now, Memory Management is kind of a mandatory chapter, to everyone!.

So what happens when you get a ‘BAD_ACCESS’ crash?. There are just so many scenarios that can trigger that crash… but the most common is simply a message sent to a dealloc’ed object.

Objective C runtime comes with a really powerful feature: Zombies!. By setting a flag, ‘release’ objects are, internally, replaced by a ‘placeholder object’.

What’s the meaning of this?. Simple!. ObjC runtime helps you determine if there is any released object that’s getting sent a message. If that’s the case, you’ll get a message in Xcode console.

How do we enable Zombies?. Mmmmmm… in Xcode 4.3.2, you need to do this:

1. Product >> Manage Schemes >> Bottom left corner… ‘Edit’
2. Select ‘Run’ in the left column
3. Select the ‘Arguments’ tab
4. Add an ‘Environment Variable’ called NSZombieEnabled, with ‘YES’ as value.

Important: Remember to remove this setting after you’re done. Otherwise, ‘Leaks’ instrument will be… useless!

 

Using ‘performSelector: withObject: afterDelay:’!

Sometimes, when developing an iOS application, we need to do something like ‘displaying a spinner’, and right after that, do a tedious task, such as query’ing a database, sorting a file, or hitting a backend.

As you may (or may not know)… all of the UIKit framework works on the Main Thread (with several exceptions, set aside). A common problem we might encounter is that… if you begin a long process after initializing an ActivityIndicatorView, the main thread will remain locked out, and thus… the spinner will never begin.

The easiest solution i could come up with looks something like this:

[cc lang=”objc”]
[_spinner startAnimating];

[self performSelector:@selector(doSomething:) withObject:someObject afterDelay:0.1f];

[/cc]

What’s this??. Simple!. We’re scheduling the ‘doSomething’ selector, in the current runloop, to be executed after 0.1 seconds. That ‘leaves room’ for the mainThread to initialize the spinner (which, internally, will spawn another thread).

That way your app won’t get a nasty freeze … and the spinner will keep on rocking!

Preventing Paste in UITextField

Suppose that your app has a custom keyboard (or component) which populates an UITextField. So… suppose that you need to enable the User Interaction with that control. However, you don’t wanna anyone pasting values right there… because you wanna force the user to rely on your custom keyboard.

UITextField lacks a ‘disablePaste’ property. In order to do this, we’re gonna need to subclass UITextField. Our subclass should look like this…

[cc lang=”objc”]
@interface MyTextField : UITextField
{
BOOL _disablePaste;
   BOOL _disableCut;
   BOOL _disableSelect;
}

@property (nonatomic, assign) BOOL disablePaste;
@property (nonatomic, assign) BOOL disableCut;
@property (nonatomic, assign) BOOL disableSelect;

@end
[/cc]

Nice, ha!?. Let’s see the actual implementation, now!:

[cc lang=”objc”]
@implementation MyTextField

@synthesize disablePaste = _disablePaste;
@synthesize disableCut = _disableCut;
@synthesize disableSelect = _disableSelect;

– (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if ( _disablePaste && action == @selector(paste:) )
{
return NO;
}
else if ( _disableCut && action == @selector(cut:) )
{
return NO;
}
else if ( _disableSelect && (action == @selector(select:) || action == @selector(selectAll:)) )
{
return NO;
}
else
{
return [super canPerformAction:action withSender:sender];
}
}

@end
[/cc]