Advertisements

Interesting Issue with iPods and Launching Your iOS App


This isn’t documented anywhere that I can tell but here’s what was happening.

I was testing a universal iOS app that I was working on and decided to just use the iPod Touch (iOS v4.2.1) I had out at the time. Unfortunately when I’d launch the app a black screen would appear with the standard status bar and nothing else. I put a breakpoint in application:didFinishLaunchingWithOptions and found that it wasn’t getting called. Strangely the app worked fine on my old iPhone 3g (iOS v4.2.1). I put the iPod aside and decided to come back to it later. Well today was later.

After playing around getting the app ready to submit to the app store I discovered that the same issue was appearing on my iPhone. After futzing around with it for a little bit I realized that I had deleted the “Main nib file base name (iPhone)” key from the application’s plist file. I restored the setting telling the app to launch “MainWindow_iPhone” and all was well but that got me thinking that maybe I didn’t test this properly on the iPod. I tried launching the app on the iPod and still no dice. I figured I was on the right track so for fun I added the “Main nib file base name” key into the plist file and set it to “MainWindow_iPhone”.

MAGIC!

So the end result is the app works on all devices now and I have three “Main nib file” keys in my plist. One for iPad, one for iPhone and one generic one.

Advertisements

Ad-Hoc App Distribution with XCode 4


Update (12-02-2011): The process of deploying to the app store was fairly simple using this new archive process. The only catch was editing the scheme to change the Archive option to use the AppStore code signing identity and using the Submit button instead of Share. Check out the app in the iTunes AppStore – Autograph This!

So amongst the many nice features in XCode 4 comes the modified process for building your app for distribution. And with “The Google” not being entirely helpful about the process as well as the docs on the Apple developer site still containing the XCode 3 instructions I thought it would help at least somebody out there for me to document the process. Please note that since I haven’t built one yet for distribution to the app store this just covers ad-hoc distribution. Maybe I’ll update this when we release to the app store.

Interacting with the provisioning portal hasn’t changed. You still need to create your distribution profile and download it to your development machine. Once you’ve done that is where the process has changed.

Read more of this post

The myth of Android fragmentation vs. iOS


With my planned move to Android from iOS as soon as I can get my hands on a good LTE phone I get a lot crap from Apple fans about Android fragmentation and carrier updates and whatnot. I hear all the time about how iOS is better because you can get access to updates quicker. They have a point. When the latest version of iOS is released I can get it immediately (actually sooner since I’m an iOS developer). I know I can root an Android phone to get the latest versions but having to jailbreak my iPhone to get the features I want is one of the reasons I’m switching to Android and this just seems like it should be unnecessary (I probably will anyway).

So I was curious recently when I saw some stats regarding iOS version adoption: Developer stats say 90 percent of iOS device users run iOS 4.x! iOS 4 is the latest major version release from Apple. I wondered how Android stacked up and this is where I feel Android loses a little bit in the message.

What is the latest version of Android for phones? 2.3
How many users have it? 0.8%

Looks bad on the surface. However by using the same criteria in the iOS article let’s ask the question a different way.

What is the latest major version of Android for phones? 2
How many users have it? Nearly 90% (http://developer.android.com/resources/dashboard/platform-versions.html)

So from a developer’s perspective I can count on the same percentage of iOS users to have the latest major version as Android OS users regardless of minor version updates. The problem is in the marketing of the OS. Android touts it’s minor releases as major ones. In my world version 2.3 isn’t supposed a major upgrade from 2.2. But they give them fancy names like Cupcake and Froyo and now it sounds like a major revision.

What it boils down to is two different update procedures that seem to result in similar statistics. With Android it is up to the carriers/manufacturers to release the updates and when they do it is OTA so everyone gets it. With iOS everyone (almost) has access to the latest version but you need to plug in to get it and that’s just not always going to happen.

UINavigationController as a Modal View


On my current iPhone project I need to display an Options view that will behave as a navigation controller with a main table view and associated subviews. I was able to accomplish this using various sources out there but feel the need to compile it all in one place.

For the purposes of this example I have a main view controller and a secondary view controller. The main view controller is the primary view controller for the application and the secondary view controller will be the root view controller of the navigation controller. Let’s also assume that I have a NIB file for the secondary view controller. In my application I wish to show a UINavigationController modally as the help section.

Changes to MainViewController.h:

#import "SecondaryViewController.h"

@class SecondaryViewController;

@interface MainViewController : UIViewController { SecondaryViewController *secondaryViewController; UINavigationController *navController;}

- (IBAction)navigateToSecondaryViewController;

@end

All I’ve done here is tell the main view controller where to find the secondary view controller and then assign it as a delegate to the secondaryViewDelegate protocol which will be defined in SecondaryViewController.h. I also created a quick IBAction method to tie to any button on the view.

Changes to MainViewController.m:

(IBAction) navigateToSecondaryViewController { if (secondaryViewController == nil) {  informationTableViewController = [[SecondaryViewController alloc]                    initWithNibName:@"SecondaryViewController"                     bundle:[NSBundle mainBundle]];  secondaryViewController.delegate = self; }

 if (navController == nil) {  navController = [[UINavigationController alloc]        initWithRootViewController:secondaryViewController]; }

 [self presentModalViewController:navController animated:YES];

}

- (void)closeSecondaryViewController { [self dismissModalViewControllerAnimated:YES];}

- (void)dealloc { if (secondaryViewController != nil) {  [secondaryViewController release]; }  if (navController != nil) {  [navController release]; }        [super dealloc];}

In my navigateToSecondaryViewController method I now initialize my view controllers if necessary. Assign the secondary view controller (which contains the information I want to display) to the navigation controller and display it modally. The closeSecondaryViewController method is the delegate method from the SecondaryViewController class which we will define next.

 

SecondaryViewController.h:
#import 

@protocol SecondaryViewDelegate 

- (void)closeSecondaryViewController;

@end

@interface SecondaryViewController : UIViewController { id delegate;}

@property (assign) id delegate;

@end/uikit.h>/uikit.h>/uikit.h>/uikit.h>
Define the header for the secondary view controller, define a protocol with a single method and create a delegate property for calling the delegate method. 

SecondaryViewController.m

#import “SecondaryViewController.h”

@implementation SecondaryViewController

@synthesize delegate;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {  self.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;    }    return self;}

- (void)viewDidLoad {    [super viewDidLoad];

 UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] init]; closeButton.title = @"Done"; closeButton.target = self; closeButton.style = UIBarButtonItemStyleDone; [closeButton setAction:@selector(closeButtonTouch)];

 self.navigationItem.title = @"Options";

 self.navigationItem.rightBarButtonItem = closeButton; [closeButton release];}

- (void)closeButtonTouch { [delegate closeSecondaryViewController];}

- (void)dealloc {    [super dealloc];}

@end
 
In the initWithNibName method I've just modified the animation style for displaying this view modally. The default is to slide in from the bottom of the screen. In the viewDidLoad method I just create a button to close the view, add it to the navigation item for the view controller and assign it a selector method. The selector method calls the delegate method that will close the view.

 

Ripple Effect on the iPhone


So on this iPhone App I am working on I am trying to create an effect on a image such that if you touch any part of the image the app will simulate a water ripple effect out from the touch point. After a few hours of research it became clear to me that I would have no choice but to attempt this effect using OpenGL ES which I had been trying to avoid. However I discovered this excellent tutorial complete with project template that made things a lot easier:

http://iphonedevelopment.blogspot.com/2009/05/opengl-es-from-ground-up-table-of.html

Using this tutorial I was able to create my texture map and apply an image to it. From there it just became a matter for coding the ripple effect. Here is what I came up with:

-(void)update:(float)time{ int i;  for( i = 0; i < (80*120*6); i++ ) {  int index = i * 3;  float *vertArray = (float *)originalVertices;

  Vertex3D v = { vertArray[index], vertArray[index+1], vertArray[index+2] };
CGPoint vect = CGPointMake(position.x - v.x, position.y - v.y);  CGFloat r = sqrtf(vect.x*vect.x + vect.y*vect.y);

  if ( r < radius )  {   r = radius - r;   CGFloat rate = powf( r / radius, 2);   v.z += (sinf( time*(CGFloat)M_PI*waves*2 + r * 0.1f) * amplitude * amplitudeRate * rate );
}

  float *vertArray2 = (float *)vertices;  vertArray2[index] = v.x;  vertArray2[index+1] = v.y;  vertArray2[index+2] = v.z; }

}

I still have a ways to go to finish it but here’s what is going on so far. First I’m looking through all of my vertices in my texture map. My texture map is 80×120 and for each point I am actually am creating 6 vertices to render a square. I know this can be optimized using GL_TRIANGLE_STRIPs but I’m not there yet. Then I create the vector and distance (r) from the touch point.

Assuming I am within the radius of the ripple I defined (which I could make dynamic down the road based on touch time) I then calculate the new depth (z) of the vertex I am on using the amplitude and other values that were set previously. After that I just update the vertices to render with the new values and it’s good to go.

I still have to handle multiple touches and other factors but what I ended up with so far is pretty cool. I’ll post a video of the effect once I’m done.

 

To Retain or Not To Retain?


Ran into an interesting thing doing iPhone development yesterday.

I needed to pause an NSTimer object (which, of course, you can’t). So to work around this I was storing the start time of the timer in a class level NSDate object using the following.

In the header file:

NSDate *startTime;


and in the class file:

startTime = [NSDate date];

I did under the assumption that using the [NSDate date] static method would behave similar to the timer method I was using to start the timer. However when I would try to access the startTime object later it was deemed out of scope by the debugger.

I changed my line of code to look like this instead:

startTime = [[NSDate date] retain];

Basically I’m now explicitly retaining the value of startTime (which also means I have to release it later). What I don’t like is the inconsistency with the static method used to create a timer. I don’t need to explicitly retain the NSTimer object so why do I need to explicitly retain the NSDate object?