I'll be speaking at the Mobile East developer conference next week, on Advanced iOS Development.
Session details are here for your viewing pleasure. Selected highlights:
This presentation will take you from a basic level of understanding of iOS to look at advanced topics that will make you apps more polished, better designed and, ideally, more successful.
Abstract concepts are no use, so in this talk we'll take some existing successful commercial iOS applications as a case study, and see how a selection of iOS technologies and techniques combine within it.
Showing posts with label ios. Show all posts
Showing posts with label ios. Show all posts
Friday, 22 June 2012
Tuesday, 3 January 2012
Speaking: BCS Newcastle
I will be speaking at BCS Newcastle on the 25th January. I'll be giving my iOS development talk; a quick start in developing applications for iPhone, iPad, and iPod Touch.
Here's the synopsis:
The iPhone, iPad and their iOS relatives are becoming an increasingly popular and important platform. More and more developers are looking into what the platform can offer and how to harness its power for their products.
In this presentation, an experienced iOS developer provides a boot-strap in iPhone development. The talk is an overview of how to get started as an iPhone developer. You will gain an understanding of the platform, the tools, and the core technologies, including:
We’ll see the pros and cons of iPhone development. You will leave with an understanding of how to deploy your applications on the device, and whether it is the right platform for you to target.
Here's the synopsis:
The iPhone, iPad and their iOS relatives are becoming an increasingly popular and important platform. More and more developers are looking into what the platform can offer and how to harness its power for their products.
In this presentation, an experienced iOS developer provides a boot-strap in iPhone development. The talk is an overview of how to get started as an iPhone developer. You will gain an understanding of the platform, the tools, and the core technologies, including:
- The main languages: Objective C/C++
- Using the Xcode IDE, and various deployment/testing tools
- Common iPhone/Mac OS design patterns, idioms, and practices
- Becoming a native: how to “think in iPhone”
- An overview of the libraries and facilities that exist
- Limitations of the development environment.
We’ll see the pros and cons of iPhone development. You will leave with an understanding of how to deploy your applications on the device, and whether it is the right platform for you to target.
Thursday, 24 November 2011
PGMidi moved and updated
Please update your repos accordingly.
Over the next few days, I'll also be adding a few new tweaks and features to the project, so stay tuned.
Thanks for all the kind comments and feedback about the code - I'm really glad it's useful. Please do let me know if you've incorporated it in your own project.
Sunday, 9 October 2011
My latest iOS app: The Mahjong Score Book
My latest iOS app is out now (thanks to the iOS 5 SDK having finally gone GM). It's called the Mahjong Score Book and, as the name suggests, is designed to help Mahjong players keep tabs on their scoring in Mahjong games.Of course, once you have your scores captured inside a wee computer, there's more exciting things we can do with them. So the app allows you to:
- keep records of all the games you've ever played, with a very clear visual presentation, associated with the date played
- draw pretty graphs of game progress
- adopt different rule sets (limit hand value, maximum wins as east wind, etc)
- export games to databases, as images, or text files
- automatically roll dice to determine starting positions
- associate notes with each game
- and much more.
If you're interested, then check it out in iTunes here.
I appreciate that it's a niche app. It simply something I wrote to fulfil a personal need. Of course, someone else out there is going to find it useful, too. And so I've polished it, honed it, and produced a really very slick app.
I wrote Mahjong Score Book app back in the summer whilst on holiday, playing Mahjong with friends. It serviced its purpose well then and many times since, and I've learnt a few new iOS techniques whilst polishing off the application.
I'm sure that it won't make me millions, but I'm very proud of what I've produced in a relatively short time. If you know someone who plays Mahjong then please point them at it!
Wednesday, 21 September 2011
iOS: Using older SDKs with newer Xcode versions
When you update Xcode versions, the installer automatically removes any old SDKs you have lying around, and replaces them with the latest version.
This is fine behaviour, as the most recent SDKs remain backwards compatible. You can set your project to target older iOS versions. If you do this, the newer SDK features are disabled for you.
However, there are times when you need to use an older SDK.
For example, I am running the latest Xcode with a beta iOS 5 SDK installed. Since this was originally installed on a clean machine, I didn't set the beta install to use a parallel directory and leave the "release version" of the developer tools intact - they simply weren't installed. (Making a parallel install is, in general, the best practice when installing a beta Xcode/SDK set).
Fear not. You can still get your newer Xcode to build with an older SDK, without downgrading your Xcode or making a parallel install:
This is fine behaviour, as the most recent SDKs remain backwards compatible. You can set your project to target older iOS versions. If you do this, the newer SDK features are disabled for you.
However, there are times when you need to use an older SDK.
For example, I am running the latest Xcode with a beta iOS 5 SDK installed. Since this was originally installed on a clean machine, I didn't set the beta install to use a parallel directory and leave the "release version" of the developer tools intact - they simply weren't installed. (Making a parallel install is, in general, the best practice when installing a beta Xcode/SDK set).
Fear not. You can still get your newer Xcode to build with an older SDK, without downgrading your Xcode or making a parallel install:
- Close any running Xcode instance you have open.
- Locate the install DMG for an old version of Xcode (e.g. Xcode_3.2.5_and_ios_sdk_4.2_final.dmg, they name them so well) and open it.
- Do not run the installer!
- Open the Packages directory in that disk image. It is a hidden directory. Try this terminal incantation: "open /Volumes/Xcode\ and\ iOS\ SDK/Packages"
- Locate the iPhoneOS and iPhoneSimulator SDKs for the version you want. Run just those pkg files. (e.g. I ran the iPhoneSDK4_2.pkg and it's matching iPhoneSimulatorSDK4_2.pkg)
- Make sure you specify the /Developer directory as your install location. If you don't, the SDKs will be installed in your root directory, under the /Platforms directory; you'll have to manually copy them into /Developer/Platforms yourself.
- Now, re-open Xcode. If the SDKs installed in the right locations, they will be selectable in your project now.
Friday, 22 July 2011
Xcode: Determining the current SDK version in a script
In an iOS XCode project, I needed a shell script target (aka "External Build Tool" target) that invokes other scripts which in turn build stuff using Xcode. Curiously recursive.Now, I needed to pass that script the current iOS SDK version being used so it could arrange its own build malarkey, and get all its SDK ducks in a row.
There is no environment variable for that defined by Xcode. Bah. The closest you get is the current deployment target version, which appears in $IPHONEOS_DEPLOYMENT_TARGET.
That seems like rather a large omission.
You do get given $SDKROOT which is a file path to the current SDK. But that's not quite the same thing as a simple version number.
Never, fear, shell gibberish to the rescue. This is what I came up with:
SDK_VERSION=$(echo $SDKROOT | sed -e 's/.*iPhone\(OS\)*\(Simulator\)*\([0-9]*.[0-9]*\).sdk/\3/')
If you know a better way to do this, I'd love to know.
Thursday, 9 June 2011
The Enigma Continues
Version 1.4 of my cool iOS puzzle game, The Enigma Squares, has been released. Check it out here. In this version, I present you more than 80 new levels, with a number of fun, a number of fiendish, and a number of speed-trial puzzles.Check it out on iTunes now.
I've also released a new game. The Enigma Kids is a family-oriented puzzler. With child-friendly puzzles, great graphics and lots of fun, everyone will enjoy this game.
Check out The Enigma Kids on iTunes here.
Let me know what you think!
Friday, 13 May 2011
iOS: The Enigma Squares (1.2)
The Enigma Squares version 1.2 is available in the App Store now. Amongst other excitement, it adds Game Center support. You can now share your achievements and high score with other players. Woo hoo.So far, I'm very impressed at how far players have got. I'm glad the game is providing an interesting challenge!
More interesting updates are in the pipeline...
Thursday, 12 May 2011
iOS: Packaging apps store submissions from the command line (my zip broke)
How to package iOS apps for submission to iTunes Connect from the command line.I'm a firm believer in the power of the command line. I like my GUI tools as much as the next man (as long as he's a bearded Unix guru from the 1970s). But for sheer power, repeatability and flexibility you just can't beat a good script.
Which is why every project I work on has to have a simple single script that configures, builds, and packages the code, creating a well-named payload that can be installed/submitted/deployed. I feel a lot safer about the quality of a release if it's generated by a tried-and-tested script, rather than by a series of button clicks in a series of separate tools.
You know it makes sense.
iOS projects submitted to the App Store are effectively zip files with a particular directory structure. You can drive Xcode with the xcodebuild tool to build and link your distribution version of an iOS app.
However, whenever I tried to zip the project up from the command line, the Application Loader utility (what you use to submit your app to iTunes Connect) just gave bizare errors.
The CodeResources files must be a symbolic link to _CodeSygnature/CodeResources. Make certain that the bundle is on a locally-mounted volume...Application failed codesign verification. The signature was invalid, or it was not signed with an Apple submission certificate.
Well, that's nice gibberish. Not.
However, a zip archive created using the Finder's "Compress" menu entry worked fine. Very frustrating.
Don't fear! I fixed it. Here's how to do it in your very own build script: your zipper is broken; throw it out. Use ditto instead. Here's the line from my build script:
APP_FILENAME=/path/to/build/Application.appPACKAGED_FILENAME=MyGoodPackagedFilename.zipditto -c -k --keepParent --rsrc "$APP_FILENAME" "$PACKAGED_FILENAME"
Enjoy your build scripts.
Wednesday, 4 May 2011
iOS: The Enigma Squares
My first personal iOS project has finally seem the light of day. Please welcome into the world The Enigma Squares. It's an interesting (and dare I say it) entertaining block-moving puzzle game.Check it out on iTunes here.
I've produced plenty of iOS projects for my company. But this has been an entertaining personal side-project, to keep me busy through those long spring evenings.
It is actually a version of a game I first wrote (ahem) 20 years ago. Back then it was written for the Acorn Archimedes, and I sold it to a magazine for inclusion on their cover disk (remember those?) This version is a little more polished, a little more challenging, and a lot more fun.
The code's a fair bit better too, but that's another story. One that I'm sure I'll tell one day...
Let me know what you think of it!
Tuesday, 19 April 2011
Speaking: ACCU 2011 slides available
The slides from all of my ACCU 2011 talks are now available for your viewing pleasure on SlideShare.Find them here:
Thanks for all the great feedback!
If you're interested in me giving these talks for you, then get in touch.
Tuesday, 5 April 2011
iOS: A Fading AVAudioPlayer
In a recent iOS project I needed to play some background music and have it fade smoothly in and out when it starts and stops.The "play some music" part is easy. iOS give us AVAudioPlayer in the AVFoundation framework. Super sweet and easy to use. However the "fade in and out" bit doesn't come for free.
The canonical solution suggested on the web is to hand-craft some nasty looping logic to get the job done. This is 2011 and we can do better than that. And, indeed, here it is, in all it's Objective C glory.
My solution makes interesting use of categories, associative references and blocks. It's worth strolling through the implementation if you're interested in any of these. If not, you can just grab my code from the Gitorious project and use it in blissful ignorance.
1. Add a category
First, we open up our own category on the AVAudioPlayer class and define the methods we would ideally like the class to provide:
@interface AVAudioPlayer (PGFade)
- (void) stopWithFadeDuration:(NSTimeInterval)duration;
- (void) playWithFadeDuration:(NSTimeInterval)duration;
@end
That's the joys of categories - you can extend existent classes in your own application easily to make it look like methods were part of the original class interface. The common convention is to save this in a file called "AVAudioPlayer+PGFade.h".
Now client code can create a bog-standard AVAudioPlayer object, and call my new methods as if they were part of the base interface:
AVAudioPlayer *player = [AVAudioPlayer alloc] initWith...]; // however you want it set up
[player playWithFadeDuration:2.0];
2. Associative References
Now, our implementation of this is going to require some instance variables (ivars) to work with. The problem with categories is that they only allow you to add methods - you can't extend the set of instance variables defined in the class' @interface.
Or can you?
Associative references to the rescue! This is a handy Objective C runtime facility that allows you to associate another object with an existing object, with a lookup system very much like a dictionary - referenced by a void* key value.
The associated object is lifetime-managed with the original object, so when you release the parent, all associated objects are also released.
Using this facility we can "graft on" some of our own private ivars to the original class. Dirty, but effective.
One of the variables I need is a boolean variable tracking whether a fade is currently in progress. I actually expose this as a property called fading in the category interface. The implementation looks like this:
@implementation AVAudioPlayer (PGFade)
static char fadingKey;
- (BOOL) fading
{
NSNumber *number = (NSNumber *)objc_getAssociatedObject(self, &fadingKey);
return number && number.boolValue;
}
- (void) setFading:(BOOL)fading
{
objc_setAssociatedObject(self, &fadingKey, [NSNumber numberWithBool:fading], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
That's relatively simple. We just use two objective C runtime functions, objc_getAssociatedObject and objc_setAssociatedObject. For the association we use the address of a static variable - this will be an unambiguous value in the whole program. The object we store is an NSNumber object initialised with the value of our boolean.It's a simple and effective trick.
3. Blocks
The final bit is for bonus points. You can see the implementation of my fade routine in the example project code itself. It's pretty simple - I just initialise the fade state in a few more "associative reference" variables and schedule a method call with performSelector:withObject:afterDelay. Each time this is called, I adjust the AVAudioPlayer's volume, and schedule a new call if one is needed.
However, to truly perform a stop with fade, we need to ramp the audio volume down, and when it gets to zero stop the player. This could be achieved with some more state variables and clumsy logic, but iOS now provides us with blocks which are perfect for this kind of activity.
For sanity, I typedef a block (closure) type. The syntax practically identical to typedefing a pointer-to-function in C, but with ^ instead of *.
typedef void (^AVAudioPlayerFadeCompleteBlock)();
I make one more associated variable of this type, the block to call on completion:
- (AVAudioPlayerFadeCompleteBlock) fadeCompletion
{
return (AVAudioPlayerFadeCompleteBlock)objc_getAssociatedObject(self, &fadeCompletionKey);
}
- (void) setFadeCompletion:(AVAudioPlayerFadeCompleteBlock)completion
{
objc_setAssociatedObject(self, &fadeCompletionKey, completion, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
Note that blocks can be traded like objective C objects. You can retain, copy, and release them. In this case our code needs to take a copy (using the OBJC_ASSOCIATION_COPY_NONATOMIC flag). This ensures that any set block exists on the heap (persistent) rather than the default on-the-stack location.
Now, the internal "audio fade" routine need only check whether there is a completion block registered when the fade is complete, and if so call it:
if (fadeIsComplete)
{
self.fading = NO;
AVAudioPlayerFadeCompleteBlock completion = self.fadeCompletion;
if (completion) completion();
self.fadeCompletion = nil;
}
Invoking a block looks just like calling a function. Once called, we clear out the stored block in case it is holding other resources that should be released.
This provides an elegant way to perform any arbitrary action after the fade is complete.
That's all, folks!
The trio of Objective C facilities used here work together well to provide a simple and elegant solution to a problem that is often achieved with complex "strings-and-glue" logic. Check out the entire project on Gitorious here.
Friday, 18 March 2011
iOS: Prettier auto-rotation

A simple Friday iOS coding tip for you:
When your app auto-rotates do you have an unsightly white frame appearing around the edges of your beautifully hand-crafted UI?
The simple fix to your UI woes: make the UIWindow background clear (either in the XIB file, or just before your call to [window makeKeyAndVisible].
Simples!
Wednesday, 16 March 2011
[ios] iOS Development talk slides available
The slides from my popular iOS development talk, last given at BCS Edinburgh are available for you to view on Slideshare.To view them, follow this link.
Friday, 11 February 2011
[ios] Dynamic cast in Objective-C
In C++, you can cast a pointer between two (related) types, and ask the runtime to check if the conversion is valid using dynamic_cast. Usually in C++ the use of dynamic_cast is a sign that you're doing something wrong - good C++ design generally avoids such constructs.
However, Objective-C is a far more dynamic language, and often you do need to do something similar. The runtime provides all the smarts for this, but doesn't deliver it in a simple one-liner.
So let's fix that...
Wondering if a view controller's view property is a UISwitch? Try this:
UISwitch *switch= objc_dynamic_cast(UISwitch,viewController.view);if (switch) NSLog(@"It jolly well is!);
That's nice, isn't it? Here's how:
#define objc_dynamic_cast(TYPE, object) \
({ \
TYPE *dyn_cast_object = (TYPE*)(object); \
[dyn_cast_object isKindOfClass:[TYPE class]] ? dyn_cast_object : nil; \
})
For the curious, here's what's going on...
First, we define a preprocessor macro using a gcc extension: the macro compound statement. That's the ({ ... }) block. This is a little dirty, and I certainly wouldn't use a gcc-specific extension in my "portable" C++ code. However, Objective-C lives in a different ecosystem, where you can guarantee that compound statements will be supported. So we'll go with it.
The reason I use a compound statement is to define a "local" variable - dyn_cast_object. This is just to cover the macro's back - it needs to mention the name of the object argument twice, and if that expression has side effects you'd get twice the number of side effects otherwise. Side-side effects. So I store the argument in a local variable to avoid this. (Most of the time this is unlikely to be an issue, but if you ever got bit by this problem, you'll appreciate having done it right the first time).
Then we simply ask the object is it is of the class of our cast's destination type, using NSObject's isKindOfClass: selector.
Not too complex. And you could do the isKindOfClass: dance wherever you need to cast. But it's nice to write the macro once and then write clear code that reveals it's intent.
[ios] Cancelling a UIGestureRecognizer
Sometimes, you still need to respond to other user interaction, and cause any pending gesture to immediately fail. There isn't an API for that.
I had this issue when my application's "timeline" view, which was using pinch, tap, and pan gestures in concert, needed to grow temporary UIButton subviews. The buttons worked fine, but pressing them also triggered the gesture recognizers - very confusing for the user.
Here's the solution.
How to forcibly cancel a UIGestureRecnogizer
Add a new category (I call it "Cancel") to the UIGestureRecognizer class extending it with a new cancel method:
@interface UIGestureRecognizer (Cancel)- (void)cancel;@end
And implement the new method like this:
@implementation UIGestureRecognizer (Cancel)- (void)cancel{self.enabled = NO;self.enabled = YES;}@end
The simple trick of switching off and back on a gesture will force it to cancel.
Then for bonus points, I add a category on UIView to make it easy to cancel all the gestures attached to it. I tend not to hold the gestures as member variables in my view controller because there isn't any need to do so - they are retained by the view you attach them to.
//-----------------------------------------// In .h file:@interface UIView (CancelAllGestures)- (void) cancelAllGestureRecognizers;@end//-----------------------------------------// In .m file:@implementation UIView (CancelAllGestures)- (void) cancelAllGestureRecognizers{for (UIGestureRecognizer *gesture in self.gestureRecognizers){[gesture cancel];}}@end
This new method could then be easily used in my main view controller, by attaching it to the my UIButton objects as a new action:
[button addTarget:myViewWithGesturesaction:@selector(cancelAllGestureRecognizers)forControlEvents:UIControlEventTouchDown];
Categories are a useful Objective C feature that really do help to make your code more clear and readable. Here they provide the means for another simple solution. I hope you find it useful.
Friday, 4 February 2011
PGMidi updated
Attention PGMidi users! I've updated my MIDI Monitor example project again, this time making PGMidi less of an example, and a lot more useful for general use.
Check it out on the GitHub project page (historical note: it was hosted on this gitorious project page, but that is now deprecated in favour of GitHub).
What's changed:
- The PGMidi class now allows you to determine what MIDI sources and MIDI connections are currently available.
- It allows you to determine whether the source/destination is a networked session, or a physically attached device.
- The "events" PGMidi sends through the delegate interface are far more explicit.
- I've added some useful tools to find a matching source/destination pair if you want to speak to one specific MIDI device.
The MIDIMonitor example application continues to show how to use the PGMidi API.
Thanks for all the comments and feedback I've received about this code. I hope you find these updates useful.
Friday, 28 January 2011
Speaking: BCS Edinburgh (iOS development)
I will be speaking at the Edinburgh branch of the BCS on the subject of iPhone development on March the 9th.
The details of the session, times, and location are available here.
Here's the synopsis:
Developing applications for iPhone, iPad (and other iOS devices)
"An introduction to iPhone development for beginners or those who are casually interested and want a leg up the learning curve"
The iPhone, iPad and their iOS relatives are becoming an increasingly popular and important platform. More and more developers are looking into what the platform can offer and how to harness its power for their products.
In this presentation, an experienced iOS developer provides a boot-strap in iPhone development. The talk is an overview of how to get started as an iPhone developer. You will gain an understanding of the platform, the tools, and the core technologies, including:
- The main languages: Objective C/C++
- Using the Xcode IDE, and various deployment/testing tools
- Common iPhone/Mac OS design patterns, idioms, and practices
- Becoming a native: how to "think in iPhone"
- An overview of the libraries and facilities that exist
- Limitations of the development environment.
We'll see the pros and cons of iPhone development. You will leave with an understanding of how to deploy your applications on the device, and whether it is the right platform for you to target.
Thursday, 27 January 2011
iOS: performSelectorOnMainThread: with two arguments
iOS's NSObject class provides a mechanism to run any selector on a different thread. The most often used variant runs the selector on the "main" (i.e. UI) thread, the snappily titled: performSelectorOnMainThread:withObject:waitUntilDone:. However, the limitation with this call is that you can only supply one argument.
Sometimes, one is not enough. There is a two argument non-thread version, here. So why not invent our own two-argument threaded version?
We can add this easily enough to the base NSObject class by opening a new category on it just for the purpose.
Here's how...
1. Define our API
We open a category on NSObject (note the category name in brackets)
@interface NSObject (PGPerformSelectorOnMainThreadWithTwoObjects)- (void) performSelectorOnMainThread:(SEL)selector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait;@end
Naturally, it follows the existing performSelector API signatures, but just adds our extra withObject: argument.
2. Implement it
Here's the secret sauce. Careful application of NSMethodSignature, and NSInvocation.
@implementation NSObject (PGPerformSelectorOnMainThreadWithTwoObjects)- (void) performSelectorOnMainThread:(SEL)selector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait{NSMethodSignature *sig = [self methodSignatureForSelector:selector];if (!sig) return;NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];[invo setTarget:self];[invo setSelector:selector];[invo setArgument:&arg1 atIndex:2];[invo setArgument:&arg2 atIndex:3];[invo retainArguments];[invo performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];}@end
That's it.
Now you have your own simple way to invoke a call to selector on the main thread from wherever you are in your code. Handy.
Wednesday, 5 January 2011
More iOS MIDI (using networked MIDI connections)
My iOS MIDI I/O example code has been incredibly popular. It's great to know that many music apps out there have incorporated my code to get their MIDI interfacing working.
Thanks for all the kind feedback.
I have been updating the MIDI code with a few structural tidy-ups, and an often requested feature - the ability to use networked MIDI sessions (connections).
Doing it manually: Using networked MIDI connections
iOS provides some a neat networked MIDI connection facility. However, despite being easy to set up, network MIDI sessions aren't initially obvious.
First, you must include:
#import <CoreMIDI/MIDINetworkSession.h>
Because network sessions are not included in the umbrella CoreMIDI.h include file. Sigh.
Next you must establish a network session by winking the (evil) singleton instance into existence:
MIDINetworkSession* session = [MIDINetworkSession defaultSession];
Then, merely turn it on:
session.enabled = YES;session.connectionPolicy = MIDINetworkConnectionPolicy_Anyone;
Yes, that is all.
Documentation for MIDINetworkSession is available here.
The easy way: using PGMidi
If you're using my MIDI classes, then you can just call the PGMidi class' enableNetwork: method with YES or NO.
Get the code
The latest version of my MIDI interface code, and a sample project that shows it in action is available from the GitHub project page.
Feedback, as ever, is welcomed.
Subscribe to:
Posts (Atom)
