Friday, December 18, 2009
iPhone Development: My struggle with the distribution provisioning profile
Friday, December 18, 2009
0 Comments
It began with a simple distribution provisioning profile creation and installation. I cleaned my targets and ran a build. No problems. I zipped up the bundle, uploaded it & got a signing error. Hmm. I googled about it and found tons of information about the problem - all with different solutions - some very labor intensive.
I checked my project build settings - I was setting to iPhone Distribution: Eric Dolecki. I then checked my target build settings - it was set to iPhone Developer (Eric Dolecki). Aha I thought. I changed the provision to distribution. Same error on upload.
I revoked the previous distribution provisioning profile and generated a new one. The expiration date was Saturday December 18th which was wrong... but whatever. I installed that and tried again. Same error.
I then changed the settings to iPhone Distribution (without my name trailing the title) & bam! It linked my name with the distribution profile and thus I was able to upload my bundle! Yay!
This didn't make a lot of sense to me (why have the generic distribution profile work & link up and the one with my actual name in it not work). I'm glad I finally figured it out & now await my approval.
Labels: iPhone
Wednesday, October 21, 2009
iPhone: UIWebView with images
Wednesday, October 21, 2009
0 Comments
One thing to note... if you want to populate your HTML dynamically, you can compose an NSString, etc. with your HTML in it so that you can dynamically populate information based on your code.
The code below sets this up and loads an html file into a webview properly so that you can reference the images easily.
- (void)viewDidLoad { NSString *mainPath = [[NSBundle mainBundle] bundlePath]; NSURL *baseURL = [NSURL fileURLWithPath:mainPath]; NSString *path = [[NSBundle mainBundle] pathForResource:@"default.html" ofType:nil]; NSString *pageHTML = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:nil]; [webView loadHTMLString:pageHTML baseURL:baseURL]; [super viewDidLoad]; }This will make things a whole lot easier when pulling images, etc. into your HTML in your UIWebView. This is pretty common knowledge, but I still had to Google around to find out why my images weren't being loaded properly.
Labels: iPhone
Tuesday, October 20, 2009
Build Succeeded. It would make a great shirt.
Tuesday, October 20, 2009
0 Comments

When you're squashing bugs, replacing methods, and you're arms are covered in delegate dust, Seeing that pop up on compile is a welcome sight. In fact, I am wondering if anyone has made a custom t-shirt with this thing in mind and attended a Macworld. I'm sure someone must have at some point.
Now to break this build and add more stuff.
Labels: iPhone
Tuesday, August 18, 2009
AS3 Developers and the iPhone
Tuesday, August 18, 2009
0 Comments
For a long while, the most exciting content on the web has been developed within the fold of the Flash Community. The Flash Community is an organic, open network of creative and devoted people constantly pushing the boundaries of cool, interactive, data-driven, and experimental. I am not going to get into a debate of AJAX versus Flash versus Silverlight, or anything like that... because I simply don't think you can bring Flash down to compare it to the others.
Of the hordes of Flash Developers, many have dipped their toes into the world of Xcode, Objective-C, and the iPhone SDK. I am seeing iPhone sessions popping up in many Flash conferences. I am seeing hardcore Flash developers (many for ages) twittering about various Obj-C methods, blogging about iPhone development, etc.
This is exciting because the iPhone itself is a platform that brings me a lot of satisfaction developing for. It's not Flash in terms of it's immediacy (at least not for me yet), but the things you can do with it after putting in some effort (googling, reading books, pouring over some code, reading header files, etc.) is astounding.
When I am developing for the iPhone, I feel like the sky is the limit and I am constantly trying to do things that were easy for me to do in Flash. Because of that Flash experience, I am able to deliver some compelling applications. And so are many other Flash developers.
The iPhone has a lot going for it in terms of apps. Yes, many throw their first few attempts on the store just to see what that feels like... but in the end we are going to be treated to a lot of wonderful content as more and more Flash developers and designers start learning Obj-C and making apps of their own.
AS3 is certainly fun. But the iPhone distraction is fun too; it's mysterious, enabling and almost as open as the Flash Community. You're still more likely to pull code out of readers on a Flash mailing list than you are on a Cocoa mailing list, but I see that softening a bit.
Anyway, this is just something I've noticed and something that I really like seeing.
Friday, August 14, 2009
iPhone: loadView and viewDidLoad
Friday, August 14, 2009
0 Comments
When I had the network detection stuff in loadView, my app would launch, go to black, and then the screen would go white... no error in the debugger... it would just stop and I'd get a blank white screen.
So I move it all into the viewDidLoad and everything behaves well now.
Does anyone know what might actually be causing this problem? I know what not to do, but I don't know why.
Labels: iPhone
Wednesday, August 5, 2009
iPhone: Image interpolation on the hack
Wednesday, August 5, 2009
1 Comments
I have three hands for this analog clock: hour, minute and second hands. They of course need to rotate to their appropriate values. However, I am using UIImageView with PNGs with transparency to do this. There are better ways to do this I'm sure, but I wanted to get this to work.
Setting it up in IB is a nightmare, so I'll be changing the way I do this for sure, but I learned a little something along the way. Using an NSTimer firing every second, I update my clock. Tick, tick, tick motions (no animation). The hands look terrible and blocky because by default no interpolation (aliasing) is happening. In trying to get rid of that, I managed to introduce some animation as well for free.
The original method called from my timer:
#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)Okay, that works, but I get horrid edges on my PNGs for the hands. Introducing these few lines before the setTransforms on the hands forces interpolation (default) and animation:
- (void) showActivity {
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit| NSMinuteCalendarUnit |NSSecondCalendarUnit;
NSDate *date = [NSDate date];
NSDateComponents *comps = [gregorian components:unitFlags fromDate:date];
int h = [comps hour];
int m = [comps minute];
int s = [comps second];
CGAffineTransform cgaRotateHr = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(h * 30));
CGAffineTransform cgaRotateMin = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(m * 6));
CGAffineTransform cgaRotateSec = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(s * 6));
[hrHand setTransform:cgaRotateHr];
[minHand setTransform:cgaRotateMin];
[secondHand setTransform:cgaRotateSec];
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
[clockLabel setText:[formatter stringFromDate:date]];
}
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath: @"transform"];Now the edges are prettier and I get animation of the hands when they change positions. It's on to looking at OpenGL and other things for something like this.
[[secondHand layer]addAnimation:animation forKey:@"transform"];
[[hrHand layer]addAnimation:animation forKey:@"transform"];
[[minHand layer]addAnimation:animation forKey:@"transform"];
Labels: CABasicAnimation, Interpolation, iPhone
Thursday, July 30, 2009
iPhone: Make your Default.png sexy
Thursday, July 30, 2009
5 Comments
I've seen where some will take their default view and snapshot that and bring it into Photoshop, and lay down a semi-transparent black on top of it to make it look disabled. Thus you snap into the view in a less jarring manner. This is a little better, but it's still not sexy.
Why not use animation? Place a UIImageView over everything and when we're done launching, remove it with a fade and some zoom? Sure... and here is some quick code to do just that:
In your YourAppDelegate.h create a reference to a UIImageView and also whip up a method you'll call through code:
@interface YourAppDelegate : NSObject <UIApplicationDelegate> {Now, in YourAppDelegate.m add the guts of that method and some additional code in your applicationDidFinishLaunching:
UIWindow *window;
YourAppViewController *viewController;
UIImageView *splashView;
}
- (void)startupAnimationDone:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;
- (void)startupAnimationDone:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {You're done. You could mess with this in other ways, but it makes the whole entry into your application a lot more appealing in my opinion.
[splashView removeFromSuperview];
[splashView release];
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
// Make this interesting.
splashView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 320, 480)];
splashView.image = [UIImage imageNamed:@"Default.png"];
[window addSubview:splashView];
[window bringSubviewToFront:splashView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0];
[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:window cache:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(startupAnimationDone:finished:context:)];
splashView.alpha = 0.0;
splashView.frame = CGRectMake(-60, -85, 440, 635);
[UIView commitAnimations];
}
Labels: iPhone
Wednesday, July 29, 2009
iPhone: MPMusicPlayerController: currentPlaybackTime and playbackDuration
Wednesday, July 29, 2009
1 Comments
Well, there doesn't seem to be one, we have access to MPMusicPlayerControllerNowPlayingItemDidChangeNotification, MPMusicPlayerControllerPlaybackStateDidChangeNotification, and MPMusicPlayerControllerVolumeDidChangeNotification. How do you like those constants? Verbose to say the least.
Anyway, I found that I had to run my own Timer, and I just started it up within viewDidLoad - every 0.5 seconds, almost like an onEnterFrame in Flash. In the end my code looks something like this... this may save you some time. The labels are IBOutlet objects, etc.
- (void)onTimer:(NSTimer *)timer {
long currentPlaybackTime = self.musicPlayer.currentPlaybackTime;
int currentHours = (currentPlaybackTime / 3600);
int currentMinutes = ((currentPlaybackTime / 60) - currentHours*60);
int currentSeconds = (currentPlaybackTime % 60);
self.currentLabel.text = [NSString stringWithFormat:@"%i:%02d:%02d", currentHours, currentMinutes, currentSeconds];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
// Initial sync of display with music player state
[self handleNowPlayingItemChanged:nil];
[self handlePlaybackStateChanged:nil];
[self handleExternalVolumeChanged:nil];
// Register for music player notifications
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(handleNowPlayingItemChanged:)
name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object:self.musicPlayer];
[notificationCenter addObserver:self
selector:@selector(handlePlaybackStateChanged:)
name:MPMusicPlayerControllerPlaybackStateDidChangeNotification
object:self.musicPlayer];
[notificationCenter addObserver:self
selector:@selector(handleExternalVolumeChanged:)
name:MPMusicPlayerControllerVolumeDidChangeNotification
object:self.musicPlayer];
[self.musicPlayer beginGeneratingPlaybackNotifications];
currentTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(onTimer:) userInfo:nil repeats:YES];
}
- (void)handleNowPlayingItemChanged:(id)notification {
MPMediaItem *currentItem = self.musicPlayer.nowPlayingItem;
self.songLabel.text = [currentItem valueForProperty:MPMediaItemPropertyTitle];
self.artistLabel.text = [currentItem valueForProperty:MPMediaItemPropertyArtist];
self.albumLabel.text = [currentItem valueForProperty:MPMediaItemPropertyAlbumTitle];
// Current Playback Value - via the running timer
// The total duration of the track...
long totalPlaybackTime = [[[musicPlayer nowPlayingItem] valueForProperty: @"playbackDuration"] longValue];
int tHours = (totalPlaybackTime / 3600);
int tMins = ((totalPlaybackTime/60) - tHours*60);
int tSecs = (totalPlaybackTime % 60 );
self.durationLabel.text = [NSString stringWithFormat:@"%i:%02d:%02d", tHours, tMins, tSecs ];
// Display album artwork. self.artworkImageView is a UIImageView.
CGSize artworkImageViewSize = self.artworkImageView.bounds.size;
MPMediaItemArtwork *artwork = [currentItem valueForProperty:MPMediaItemPropertyArtwork];
if (artwork != nil) {
self.artworkImageView.image = [artwork imageWithSize:artworkImageViewSize];
} else {
self.artworkImageView.image = nil;
}
}
Labels: iPhone
Friday, July 17, 2009
iPhone: External Accessory Framework snippets
Friday, July 17, 2009
17 Comments
Add the ExternalAccessory.framework to your project. Make sure to add #import <ExternalAccessory/ExternalAccessory.h> to your .m file, and this is some example code:
- (EASession *)openSessionForProtocol:(NSString *)protocolString {Enjoy. This is here merely as a kind of reference.
NSArray *accessories = [[EAAccessoryManager sharedAccessoryManager]
connectedAccessories];
EAAccessory *accessory = nil;
EASession *session = nil;
for (EAAccessory *obj in accessories) {
if ([[obj protocolStrings] containsObject:protocolString]){
accessory = obj;
break;
}
}
if (accessory){
session = [[EASession alloc] initWithAccessory:accessory
forProtocol:protocolString];
if (session) {
[[session inputStream] setDelegate:self];
[[session inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[[session inputStream] open];
[[session outputStream] setDelegate:self];
[[session outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[[session outputStream] open];
[session autorelease];
}
}
return session;
}
// Handle communications from the streams.
- (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent
{
switch (streamEvent)
{
// case NSStreamHasBytesAvailable: this was incorrect in Apple documentation...
case NSStreamEventHasBytesAvailable:
// Process the incoming stream data.
break;
case NSStreamEventHasSpaceAvailable:
// Send the next queued command.
break;
default:
break;
}
}
Labels: ExternalAccessory, iPhone, Objective-C
Thursday, July 16, 2009
iPhone Book: Beginning iPhone 3 Development (hold the phone)
Thursday, July 16, 2009
0 Comments

I printed tons of pages found on the internet, and I also purchased a few books on the subject. I keep two on my desk at all times: Beginning iPhone Development (Exploring the iPhone SDK) by Dave Mark and Jeff LaMarche, and The iPhone Developer's Cookbook.
I refer to them every now and then in case I forget something pretty silly and need a quick reference. And yes, I am also guilty of opening up previous Projects looking for techniques I used before that I want to employ again. I just did that twenty minutes ago.

But what's the point of this post? You see, the Beginning iPhone 3 Development book is new, but it's not completely new. A little sprinkling of Core Data has been added and some Table View styling. That's about it.
If you are into the new stuff in the 3.0 SDK (GameKit, MapKit, Push Notifications, In-App Purchase, more Core Data, etc.) then you want to wait for the book from the same guys to be called More iPhone 3 Development. So check Amazon every now and then. These guys put together really fine books, so you'll be well-served. Just don't get the new one they just put out thinking it's going to cover SDK 3.0 in any great detail.
Wednesday, July 15, 2009
iPhone: Previous example with touches
Wednesday, July 15, 2009
0 Comments
#import "ClickThroughViewController.h"
#import <QuartzCore/QuartzCore.h>
@implementation ClickThroughViewController
@synthesize imageView, imageViewTop, aboutView, aboutButton,
advanceButton, backButton, label, gestureStartPoint, dirString;
- (void)updateLabel {
NSString *c = [[NSString alloc] initWithFormat:@"%i", count];
label.text = c;
[c release];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:self.view];
dirString = NULL;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
if(fabsf(gestureStartPoint.x - currentPosition.x ) >= kMinimumGestureLength && fabsf(gestureStartPoint.y - currentPosition.y) <= kMaximumVariance){
//Horizontal Swipe
if( gestureStartPoint.x < currentPosition.x ){
dirString = @"fromLeft";
} else {
dirString = @"fromRight";
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if( [dirString isEqualToString:@"fromLeft"] ){
[self prevImage];
} else if( [dirString isEqualToString:@"fromRight"]){
[self nextImage];
}
}
/*
You need to make sure the prototype images that you use are JPGs
and use the "image_" convention, otherwise the total count will
be off and your application will bork.
*/
- (void)viewDidLoad {
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image_1.jpg" ofType:nil]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image_1.jpg" ofType:nil]];
imageView.image = img2;
imageViewTop.image = img;
imageView.hidden = YES;
totalCount = 0;
aboutShowing = NO;
NSArray *d = [[NSBundle mainBundle] pathsForResourcesOfType:@"jpg" inDirectory:nil];
for(NSString *s in d){
if([[s lastPathComponent] hasPrefix:@"image_"]){
totalCount++;
}
}
count = 1;
prev = totalCount;
label.alpha = 0;
[self updateLabel];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[imageView release];
[backButton release];
[advanceButton release];
[super dealloc];
}
// #pragma isn't very cool in my opinion, so...
//MARK: Custom Code
- (IBAction)advanceImage:(id)sender {
[self nextImage];
}
- (void)nextImage {
count++;
if( count > totalCount ){
count = 1;
}
if( count == 1 ){
prev = totalCount;
} else {
prev = count - 1;
}
[self updateLabel];
NSString *tmp = [[NSString alloc] initWithFormat:@"image_%i", count];
NSString *old = [[NSString alloc] initWithFormat:@"image_%i", prev];
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:tmp ofType:@"jpg"]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:old ofType:@"jpg"]];
imageView.image = img2;
imageViewTop.image = img;
label.alpha = 1;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:[self imageViewTop] cache:YES];
[UIView setAnimationDuration:0.5];
[UIView commitAnimations];
CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
label.alpha = 0;
[UIView commitAnimations];
}
- (IBAction)aboutChange:(id)sender {
if( !aboutShowing ){
aboutShowing = YES;
aboutView.hidden = NO;
aboutView.frame = CGRectMake(0, -50, 320, 480);
aboutView.alpha = 0.0;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationDuration:1.0];
aboutView.frame = CGRectMake(0, 0, 320, 480);
aboutView.alpha = 1.0;
[UIView commitAnimations];
} else {
aboutShowing = NO;
CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
aboutView.frame = CGRectMake(0, -50, 320, 480);
aboutView.alpha = 0.0;
[UIView commitAnimations];
}
}
- (IBAction)backImage:(id)sender {
[self prevImage];
}
- (void)prevImage {
count--;
if( count < 1 ){
count = totalCount;
}
if( count == 1 ){
prev = totalCount;
} else {
prev = count + 1;
}
[self updateLabel];
NSString *tmp = [[NSString alloc] initWithFormat:@"image_%i", count];
NSString *old = [[NSString alloc] initWithFormat:@"image_%i", prev];
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:tmp ofType:@"jpg"]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:old ofType:@"jpg"]];
imageView.image = img2;
imageViewTop.image = img;
label.alpha = 1;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:[self imageViewTop] cache:YES];
[UIView setAnimationDuration:0.5];
[UIView commitAnimations];
CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
label.alpha = 0;
[UIView commitAnimations];
}
@end
Labels: iPhone, Objective-C
Monday, July 13, 2009
iPhone: Voices That Matter iPhone Developers Conference
Monday, July 13, 2009
0 Comments
You can check out details of the conference right here. Just to get you're nether bits in an excited state, Aaron Hillegass is delivering the Saturday keynote and Andy Ihnatko is delivering a talk on Sunday. Topics include:
- Custom User Interfaces with Core Animation
- Data Sync
- Designing a Killer UI
- iPhone View Controllers
- Peer to Peer Networking
- Cocoa Design Patterns
- Core Data
- Open GL ES for General Applications
- Rapid Application Delivery: Going Hybrid
- Accelerometer
- Audio and OpenAL
- Core Location
- Cameras and Photos
Labels: Conference, iPhone
Friday, July 10, 2009
iPhone: Easy step through presentation application
Friday, July 10, 2009
2 Comments
The code reads JPG images that use "image_" in their filename. That allows you just load up your project with the files you want and they end up in the bundle, available to you. You could tweak this to use online assets too if you really wanted.
Enjoy on this fine Friday.
#import "ClickThroughViewController.h"
#import <quartzcore/quartzcore.h>
@implementation ClickThroughViewController
@synthesize imageView, imageViewTop, aboutView, aboutButton, advanceButton, backButton, label;
- (void)updateLabel {
NSString *c = [[NSString alloc] initWithFormat:@"%i", count];
label.text = c;
[c release];
}
/*
You need to make sure the prototype images that you use are JPGs
and use the "image_" convention, otherwise the total count will
be off and your application will bork.
*/
- (void)viewDidLoad {
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image_1.jpg" ofType:nil]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image_6.jpg" ofType:nil]];
imageView.image = img2;
imageViewTop.image = img;
imageView.hidden = YES;
totalCount = 0;
aboutShowing = NO;
NSArray *d = [[NSBundle mainBundle] pathsForResourcesOfType:@"jpg" inDirectory:nil];
for(NSString *s in d){
if([[s lastPathComponent] hasPrefix:@"image_"]){
totalCount++;
}
}
count = 1;
prev = totalCount;
label.alpha = 0;
[self updateLabel];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[imageView release];
[backButton release];
[advanceButton release];
[super dealloc];
}
// #pragma isn't very cool in my opinion, so...
//MARK: Custom Code
- (IBAction)advanceImage:(id)sender {
count++;
if( count > totalCount ){
count = 1;
}
if( count == 1 ){
prev = totalCount;
} else {
prev = count - 1;
}
[self updateLabel];
NSString *tmp = [[NSString alloc] initWithFormat:@"image_%i", count];
NSString *old = [[NSString alloc] initWithFormat:@"image_%i", prev];
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:tmp ofType:@"jpg"]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:old ofType:@"jpg"]];
imageView.image = img2;
imageViewTop.image = img;
label.alpha = 1;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:[self imageViewTop] cache:YES];
[UIView setAnimationDuration:0.5];
[UIView commitAnimations];
CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
label.alpha = 0;
[UIView commitAnimations];
}
- (IBAction)aboutChange:(id)sender {
if( !aboutShowing ){
aboutShowing = YES;
aboutView.hidden = NO;
aboutView.frame = CGRectMake(0, -50, 320, 480);
aboutView.alpha = 0.0;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationDuration:1.0];
aboutView.frame = CGRectMake(0, 0, 320, 480);
aboutView.alpha = 1.0;
[UIView commitAnimations];
} else {
aboutShowing = NO;
CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
aboutView.frame = CGRectMake(0, -50, 320, 480);
aboutView.alpha = 0.0;
[UIView commitAnimations];
}
}
- (IBAction)backImage:(id)sender {
count--;
if( count < 1 ){
count = totalCount;
}
if( count == 1 ){
prev = totalCount;
} else {
prev = count + 1;
}
[self updateLabel];
NSString *tmp = [[NSString alloc] initWithFormat:@"image_%i", count];
NSString *old = [[NSString alloc] initWithFormat:@"image_%i", prev];
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:tmp ofType:@"jpg"]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:old ofType:@"jpg"]];
imageView.image = img2;
imageViewTop.image = img;
label.alpha = 1;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:[self imageViewTop] cache:YES];
[UIView setAnimationDuration:0.5];
[UIView commitAnimations];
CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
label.alpha = 0;
[UIView commitAnimations];
}
@end
Labels: iPhone, Objective-C, Xcode
Wednesday, July 8, 2009
iPhone: CorePlot
Wednesday, July 8, 2009
1 Comments

In order to integrate into your iPhone application, after checking the code out of the repository or downloading you can follow this information:
Because frameworks cannot be used in Cocoa Touch applications in the same way as on the Mac, the means of including Core Plot within an iPhone application are slightly different.
First, drag the CorePlot-CocoaTouch.xcodeproj file into your iPhone application's Xcode project (making sure that nothing's copied and the paths are relative to your project). Then go to the Targets tab in Xcode, select your application's target, and bring up the inspector. Go to the General settings page and add the CorePlot-CocoaTouch library as a direct dependency.
Core Plot is built as a static library for iPhone, so you'll need to drag the libCorePlot-CocoaTouch.a static library from under the CorePlot-CocoaTouch.xcodeproj group to your target's Link Binary With Libraries folder.
You'll also need to point to the right header location. Under your Build settings, set the Header Search Paths to the relative path from your application to the framework/ subdirectory within the Core Plot source tree. Make sure to make this header search path recursive. You need to add -ObjC to Other Linker Flags as well.
Core Plot is based on Core Animation, so if you haven't already, add the QuartzCore framework to your application project.
Finally, you should be able to import all of the Core Plot classes and data types by inserting the following line in the appropriate source files within your project:
#import "CorePlot-CocoaTouch.h
I have yet to try this out myself since I don't immediately have a need for it, but I am seeing some people encountering problems with the steps outlined. They get a EXC_BAD_ACCESS error. Perhaps this library isn't set up in it's downloaded form properly and may require some tinkering to get it rolling properly. Here is the Issues List where you can tool around to see what problems currently exist that have been commented upon.
Tuesday, July 7, 2009
Are you using Amazon's Product Advertising APIs? You could be in trouble.
Tuesday, July 7, 2009
0 Comments
You see, the APA APIs stipulate that use of the API is prohibited from use on a mobile device.
From the agreement: 4. Usage Requirements, (e):
You will not, without our express prior written approval requested via this link, use any Product Advertising Content on or in connection with any site or application designed or intended for use with a mobile phone or other handheld device.
So you might be in violation and not know it yet. I'd imagine an application with a small user footprint will probably go unnoticed. You may want to look into this if you are using Amazon's service.
Monday, July 6, 2009
iPhoneSimulatorExchange
Monday, July 6, 2009
0 Comments
I can see the value for the screencasts certainly, and use for other developers is neat without them having to worry about your frameworks, etc. I do think that it might almost be easy enough to zip up a project file and have another developer just compile the thing you want tested, but I could certainly be wrong about that. Check it out.
Labels: iPhone, Objective-C, Simulator
Thursday, June 25, 2009
[iPhone] Getting images from your bundle without hardcoding
Thursday, June 25, 2009
0 Comments
totalCount = 0;Update 2. Since the file structure normally gets flattened out within your iPhone application (I guess there are some compiler tricks you can do), you'll always be targeting the root of the app directory. With that in mind, you'll want to probably use some kind of naming convention to separate any special files you'd like to collect from the bundle. You can also use extension. Say collect up and get the count of all images in your bundle that are JPGs and contain "image_" in the title:
NSArray *d = [[NSBundle mainBundle] pathsForResourcesOfType:@"jpg" inDirectory:nil];
for(NSString *s in d){
if([[s lastPathComponent] hasPrefix:@"image_"]){
totalCount++;
}
}
totalCount = 0;Boom.
NSArray *d = [[NSBundle mainBundle] pathsForResourcesOfType:@"jpg" inDirectory:nil];
for( int i=0;i<[d count];i++){
NSString *searchForMe = @"image_";
NSString *s = [[NSString alloc] initWithString:[d objectAtIndex:i]];
NSRange range = [s rangeOfString:searchForMe];
if( range.location != NSNotFound ){
totalCount++;
}
}
Update. I'm a moron. I should have just looked into NSBundle.h.
NSUInteger jpegCount = [[[NSBundle mainBundle] pathsForResourcesOfType:@"jpg" inDirectory:subDirName] count];
You can get the number of a type of item in your bundle on the iPhone, and this can come in very handy. No magic numbers. This code example doesn't look in a resource directory, but you could supply the inDirectory with something like @"backgrounds" and thus build up arrays of images of differing types, etc. There may be a better way of doing this (ie. if you only want to get the count of the items), but I don't know about it yet.
NSMutableArray * imageArray = [[NSMutableArray alloc] init];Tada. I hope to find some more examples.
NSEnumerator * imageBundlePathEnumerator = [[[NSBundle mainBundle] pathsForResourcesOfType: @"jpg" inDirectory: nil] objectEnumerator];
NSString * imageBundlePath = nil;
while (imageBundlePath = [imageBundlePathEnumerator nextObject])
{
[imageArray addObject: [[[NSImage alloc] initWithContentsOfFile: imageBundlePath] autorelease]];
}
NSLog(@"Number of images loaded : %d", [imageArray count]);
NSImage * anImage = nil;
NSEnumerator * imageEnumerator = [imageArray objectEnumerator];
while (anImage = [imageEnumerator nextObject])
{
NSLog(@"image = %@", anImage);
}
Labels: iPhone, Objective-C
Thursday, May 28, 2009
Pixel formats in cocos2d v0.7.3+
Thursday, May 28, 2009
0 Comments
The texture's pixel format is the way the image is stored in GPU memory.
Possible pixel formats:
- RGBA8888 (32-bit) (kTexture2DPixelFormat_RGBA8888)
- RGBA4444 (16-bit) (kTexture2DPixelFormat_RGBA4444)
- RGB5_A1 (16-bit)(kTexture2DPixelFormat_RGB5A1)
- RGB565 (16-bit) (kTexture2DPixelFormat_RGB565)
- 8 bits are assigned to the red channel, 8 bits to the green channel, 8 bits to the blue channel and 8 bits to the alpha channel.
- Use this pixel format when you need the maximum possible quality for your image.
- But it will consume the double of memory compared to 16-bit textures. Memory is a precious resource on the iPhone
- Usually it is also slower to render.
- Useful for: background image of your intro scene, and for images with lots of gradient colors
- 4 bits are assigned to the red channel, 4 bits to the green channel, 4 bits to the blue channel, and 4 bits to the alpha channel
- It gives you good quality in all channels, good speed, good memory consumption.
- Useful for: sprites that have different values of transparency
- 5 bits are assigned to the red channel, 5 bits to the green channel, 5 bits to the blue channel, and only 1 bit to the alpha channel
- It gives you good quality in RGB channels but poor quality on the A channel. It also gives you good speed and good memory consumption.
- Useful for: sprites that have transparent parts, but the transparency is either On or Off
- 5 bits are assigned to the red channel, 6 bits to the green channel, and 5 bits to the blue channel. It has no alpha channel support
- It gives you the best possible quality for 16-bit textures, but without alpha channel support.
- Useful for: background images in your game.
How to use it:
// Set the pixel format before loading the image
// RGBA 8888 image (32-bit)
[Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
Sprite *sprite1 = [Sprite spriteWithFile:@"test-rgba1.png"];
// Set the pixel format before loading the image
// RGBA 4444 image (16-bit)
[Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444];
Sprite *sprite2 = [Sprite spriteWithFile:@"test-rgba2.png"];
// Set the pixel format before loading the image
// RGB5A1 image (16-bit)
[Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGB5A1];
Sprite *sprite3 = [Sprite spriteWithFile:@"test-rgba3.png"];
// Set the pixel format before loading the image
// RGB565 image (16-bit)
[Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGB565];
Sprite *sprite4 = [Sprite spriteWithFile:@"test-rgba4.png"];
// restore the default pixel format
[Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_Default];
Labels: cocos2d, iPhone, pixel format
Wednesday, May 13, 2009
iPhone: Detect online network status
Wednesday, May 13, 2009
6 Comments
For me this network detection thing was a bit of a Holy Grail item. I'd seen a few examples around from Apple that seemed like they used tons of code to get the job done (or maybe I just didn't understand their code well enough yet). Then I read online about a seismic XML tutorial from Apple that did network detection.
I popped open the project in the Xcode Documentation window and started checking out the .h and .m files. I saw the implementation they used, and it didn't involve tons of code. And after testing it, it works just fine for the moment.
I've since been told that I could use a separate thread and populate the initial UIImageViews with a stock image, and the threaded process would fetch and place the artwork as needed (to allow for initial smooth scrolling). I don't know enough about that yet though, so this will have to do.
Make sure you Add the SystemConfiguration.framework to your project, and include it in your .m (#import
In your .h file, define a BOOL, I called mine "availableNetwork" - you don't need to assign it as a property, just up in the interface block. Make sure you also define the method in the .h... -(BOOL)isDataSourceAvailable;
Here are the two methods I'm using to report back network status (in my .m):
- (BOOL)isDataSourceAvailable {That's the method we'll call when we load our view, and set our "availableNetwork" value to. loadView is triggered before viewDidLoad.
static BOOL checkNetwork = YES;
static BOOL _isDataSourceAvailable = NO;
if (checkNetwork) { // Since checking the reachability of a host can be expensive, cache the result and perform the reachability check once.
checkNetwork = NO;
Boolean success;
const char *host_name = "google.com"; //pretty reliable :)
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, host_name);
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
_isDataSourceAvailable = success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachability);
}
return _isDataSourceAvailable;
}
- (void)loadView {And there you have it. It's a one shot deal here, if connectivity returns, the flag won't be reset. You could always run a NSTimer that checks every now and then, or I am sure there is some kind of notification of that kind of change one could listen for... I'm not far enough along with all of this to know yet.
availableNetwork = NO;
BOOL returnVal = [self isDataSourceAvailable];
availableNetwork = returnVal;
...
Labels: iPhone, Network Status, Objective-C
Tuesday, May 12, 2009
iPhone: UITableView customization
Tuesday, May 12, 2009
1 Comments
After spending a lot of time on forums, Google, and email lists, I have a solution that should have been easier to get to. I received suggestions that I keep a pointer around for the previously selected item, so when a selection is detected I could introspect the current cell, change the text color there, and then change the previous cell's UILabels back to normal. A lot of work, and it's keeping state which is a bad idea. There were mentions of reloadData for the table, etc.
However one thing I overlooked initially was that I was thinking of the table cell as retaining it's selected state. Normally you'd just call up another view from a selection in a table. So I didn't really need to maintain the selected visual state in the table, but I needed to show it to the user.
A fine chap from Apple emailed me that most iPhone applications implement a nice animation for selected cells in a table and that I should follow that paradigm. So that got me digging.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {That bit of animation basically tells the table to deselect the selected item with animation. This works great but it doesn't reset the text color in the cell itself. That's when I stumbled onto the holy grail solution for me being able to reset the text without having to dig into the cell itself or keep a pointer around for the previous selected cell. It was simple using a property I hadn't run into yet before so I didn't know of it's existence... highlightedTextColor. DOH! That was it!
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//NSLog(@"%d:%d", [indexPath row], [indexPath section] );
// Need to get to the cell
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *cellLabel = (UILabel *)[newCell.contentView viewWithTag:1];
NSLog( @"%@", [cellLabel text] );
}
So pairing the above method with this detail in my cellForRowAtIndexPath, I get exactly what I needed:
...I set the text color (using a macro) and also the highlighted text color. So what happens is that the background transitions to my dark selected graphic while the text turns white, and upon deselection the text returns back to that 0x555555 color while the dark selected graphic fades away leaving the normal graphic for the cell.
labelThree = [[[UILabel alloc] initWithFrame:CGRectMake( 65, 34, 200, 25)] autorelease];
labelThree.tag = 3;
labelThree.font = [UIFont systemFontOfSize:10.0];
labelThree.backgroundColor = [UIColor clearColor];
labelThree.textColor = UIColorFromRGB(0x555555);
labelThree.highlightedTextColor = [UIColor whiteColor]; // Why didn't I know about this!!!
labelThree.text = [NSString stringWithFormat:@"%@", [[photoArray objectAtIndex:row] objectForKey:@"rating"]];
...
This works perfectly without me keeping state myself anywhere... let the APIs handle all of that crap for me. I burned a whole day on this simple thing, but it takes moments like these to really understand and learn (in my opinion).
Labels: iPhone, Objective-C, UITableView
Thursday, May 7, 2009
iPhone: Want to use Hex for UIColor?
Thursday, May 7, 2009
1 Comments
//This works, but come on...However, if you want to be more specific normally you need to get the RGBA for the color and set it that way. That's time consuming especially if the color may be tweaked several times before the final is settled upon. In flash we can just use Hex. Now, with this little macro, you can too & it's a HUGE time saver:
cell.textColor = [UIColor grayColor];
#define UIColorFromRGB(rgbValue) [UIColor \Shazaam!!!
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (nil == cell) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"cell"] autorelease];
}
cell.textColor = UIColorFromRGB(0x333333);
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.text = @"Testing 1 2 3";
}
Labels: iPhone, Objective-C
Thursday, May 8, 2008
Ignite Boston event
Thursday, May 8, 2008
0 Comments
O'Reilly is hosting another fun, free Ignite Boston event!
Ignite Boston is happening on Thursday, May 29, from 6 to 10pm at Tommy Doyle's in Harvard Square, Cambridge (www.tommydoyles.com). We're heading back to the venue of our first Ignite, but we're using two floors so we can accommodate more folks.
The evening's keynote speakers are:
- Jonathan Zdziarski, iPhone maven and author of "iPhone Open Application Development" (This has me more excited than anything else right now)
- John Viega, security guru and author of many O'Reilly titles, including the upcoming "Beautiful Security"
http://ignitenight.thirdeye
Presentation Guidelines:
- Be no longer than 5 minutes.
- Be on an innovative topic (no sales pitches or launches, please!).
- Be viewable on a PC with standard AV equipment.
Stay in the loop by visiting our blog for updates, speaker lists, and other info:
http://www.oreillynet.com
See you there!
And while you're waiting for Ignite...our friends at BarCampBoston are running another BarCamp on May 17th and 18th. BarCamp is a free unConference where you can participate in discussions, demo your projects, or join into another cooperative event.
Find out more and register at http://www.barcampboston.org/
Labels: BarCampBoston, boston, Flex, iPhone
Friday, July 6, 2007
Flash on the iPhone...
Friday, July 6, 2007
0 Comments
- Battery life. Someone needs to make a player that isn't Flashlite, but consumes a lot less CPU to do its rendering - taking advantage of the hardware more. I am sure the iPhone does this on its own already with all the speedy transitions. Give that to the Flash Player, and that would be a big help.
- Edge sucks, so we'd have to worry a little about the size of most Flash content, how it gets cached and eats memory, and how it would perform on a slow connection (something most of us have simply forgotten about). A caching mechanism or something could possibly help.
- The iPhone gesturing might get confused with Flash content underneath it that also sucks up mouse events? Probably not, but maybe. Depending on how the Flash was developed, it could make things weird, especially for full-screen Flash apps and websites. This is probably the easiest thing to fix.