Tuesday, December 28, 2010

Objective-C Memory Management & Garbage Collection

This article started out as a presentation I did for the Des Moines Cocoaheads.

Introduction

Objective-C Memory Management is something i've seen new people to Cocoa & Objective-C mess up in ways I could just not conceive of on my own. In reality Objective-C memory management is not that hard. You simply need to be aware of some rules and follow a couple of good development practices. Good memory management practices are a good thing to follow on any platform. You don't want to be known as "that" app that hogs lots of memory, I have switched to alternative apps a couple times because the apps I was using were fine, but consumed far too much memory. Especially on iOS you need to follow good memory practices, because otherwise you'll be struggling to deal with low memory alerts and the possibility of your app being killed by iOS.

Objective-C Retain Count

Objective-C in retain count mode (not using garbage collection) is a simple idea. When you explicitly allocate an object it gets a retain count of 1 and when you call release or autorelease on an object it's retain count gets decremented and then the object will be collected. It is the only mode available on iOS Devices and has been in use on Mac OS X since the beginning of the OS.

NSObject *object = [[NSObject aloc] init]; //retain count 1
[object release]; //retain count 0

When a object gets released -dealloc gets called on an object and its memory will be reclaimed. It's important to note that you never call dealloc on an object directly. In fact in all my time as a Cocoa Developer I've heard only 1 legitimate use of calling -dealloc on an object directly, I won't say what it is, but needless to say you would have a lot of Cocoa/Objective-C experience behind you before you would even conceive of doing this. In the same area as -release there is also -autorelease. -autorelease is the same as -release except that it'll perform the release in the future. This works great because with this an object you know you need to release in the future can be taken care of at the beginning of a method or section of code.

-(void)doFoo:(BendingUnit *)bender
{
 if(flexo)
  [flexo autorelease]; //will be sent release later
 ...


Owning an Object
In all these cases when we explicitly perform an -alloc we "own" the object, and when we call -release or -autorelease we relinquish ownership. If you call a method whose name contains 'alloc','new' or 'copy' or if you send a retain message to an object you now own the object and it is your responsibility to send it a -release or -autorelease at an appropriate time. An example of assuming ownership of an object...

-(NSInteger)numberOfInstancesOfString:(NSString *)pattrnString
{
 NSString *patternString = [[pattrnString retain] autorelease];
 NSInteger count = 0;
 // do some stuff here with the string return count;
}

In the above example we are doing something very wise. We are passed in a NSString object which may live beyond the scope of our method. So to ensure that the string lives throughout our method we are calling -retain on the string object and -autorelease on it as well so that at the end of the method it'll be restored to the state it was originally in. If this is a normal string object (retain count 1) then all we are doing is incrementing it's retain count to 2 and then at the end of the method it's retain count will be back at 1. However if we are in the middle of executing this method and somewhere else this object gets a release message then we are ensured to be able to use the object for the lifetime of the method and then the passed object will be released. Note that by calling retain on the string object we assumed ownership of the object and then also did the responsible thing and called autorelease to relinquish ownership of it at the end of the method. What happens we we don't follow the rules?

-(void)dooFoo
{
 NSString *myString = [[NSString alloc] initWithString:@"Good News Everyone!"];
 //... do some stuff
 //... oh noes we are at the end of the method and never sent release to mystring!
}

Oh Noes! At the beginning of this method we create a NSString pointer and explicitly allocate memory for a NSString object and initialize it with a NSString object. The method does some things and then it goes away. However the memory that we allocated is still there, but we no longer have a reference to that memory leaving it forever uncollectible (except under Garbage Collection.) This is a memory leak, it's memory we asked the operating system to set aside for us that we can not reclaim.


NSAutoreleasePool

Autorelease pools are a place where you can collect objects sent an autorelease message and clean them up by sending an NSAutoreleasePool a drain message. When you are running an application based on AppKit, the Cocoa Framework automatically creates a NSAutoreleasePool instance for you and drains it upon your application quitting. You can setup and drain a autorelease pool easily.

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *temp = [NSString stringWithString:@"Name:"];
NSNumber *tempNumber = [NSNumber numberWithInt:55];
[pool drain]; //collects temp & tempNumber

You can also do AutoreleasePools within other autorelease pools
int main(int argc, const char **argv[])
{
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSArray *files = //fileArray...
 for(NSString *file in files) {
  NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];

  NSError *fileError = nil;
NSString *file = [NSString stringWithContentsOfFile:file encoding:NSUTF8Encoding error:&error];
  //process file...
  [innerPool drain];
 }
 [pool drain];
}

This can be convenient, especially in iOS to allocate a bunch of objects and free them as soon as possible with an autorelease pool to keep memory pressure down. In some cases they are completely necessary if you intend to say work with Foundation in a command line tool you have to explicitly create an autorelease pool, the same goes for NSOperations main method (except for Garbage Collected apps where this is done automatically for you.)


Coding Horrors

A while before I made a presentation from the same content that is in this article I asked on twitter for some ways people had seen memory abused in Objective-C. From the responses I got back and some things I have heard from various people I won't name here a lot of people have abused Objective-C memory in odd ways. I want to feature some of them here in the hopes that you will never commit these atrocities yourself.


Exhibit 1
-(void)dealloc
{
 while([myObject retainCount] != 0){
  [myObject release];
 }
 [super dealloc];
}

This is wrong on all sorts of levels. Putting this in your code is a sure fire way to show someone how little you understand about Objective-C. First of all let me say this morvo_retain_count.png

If you've been dealing with Objective-C for a while you know that you shouldn't be using the value of retain count, it never actually goes down to zero and you should never be testing against zero anyway. In fact the only reason retain count is still in the Cocoa framework is for legacy reasons and there are a lot of developers petitioning Apple to remove retain count from Cocoa entirely. In any case, the above code should only have 1 release per object in it. If you have objects that have a retain count of 1 or more by the time they've hit this method then you have not properly released or autoreleased the object somewhere else.


Exhibit 2
MyObject *obj = [[MyObject alloc] init];
//do stuff with obj...
[obj dealloc];

Again you shouldn't call dealloc on an object directly. In fact in all of our Cocoaheads group only Eric Rocesecca (a longtime mac veteran, formerly of startly (quickeys) fame) could only come up 1 use for sending dealloc directly to an object for 1 specific case. I won't even go into that specific case, because it's really a specific niche case & beyond the scope of this article.


Exhibit 3
MyClass *obj = [[[[MyClass alloc] init] autorelease] retain];
//do stuff with obj...
[obj release]; 

In this specific example by itself the extra autorelease and retain are just extra garbage at the end since you could just have the alloc and init and do the release and have the exact same effect. This code was shown to me to be in some of Facebooks open source code.


Exhibit 4
MyClass *myObj = [[MyClass alloc] init];
//...do stuff
[myObj release];
[myObj release]; 

If you have multiple retains/releases in 1 place its a very strong signal that you have not done a proper retain release somewhere else. You should really examine your code to make sure you should be doing retain and release elsewhere.


Exhibit 5
NSAutoreleasePool *pool = //...//... do stuff
if(num != kMax)
{
 NSAutoreleasePool *pool2 = //...
NSString *myStr = //...
 //do stuff with myStr
 [pool2 drain]
}
[pool drain]; 

This is something that I could not have conceived on my own. If you are using a lot of autorelease pools and using them as a fix for memory leaks your doing something wrong. There is a legitimate use to using autorelease pools every so often as a means of releasing memory pressure, especially if you are allocating a bunch of objects at once on iOS, but you shouldn't be putting them everywhere because you detect a memory leak.


Exhibit 6
[self dealloc];
while([self retainCount])
 [self release]; 

Similar to Exhibit #1, except with 2x the stupidity. So how do we find what's wrong with our apps?

instruments_memory.png

There are several things you can do
1. Turn on the Clang Static Analyzer, I basically duplicated by debug configuration and named it Analyze and then flipped on the "Run Clang Static Analyzer" checkbox so it's always running the clang static analyzer all the time. The Clang static analyzer will point out many (but not all) places where it can see you are doing something wrong with memory
2. Periodically profile the memory use of your app
3. Run Zombies instrument on your app to track down messages sent to deallocated objects

Objective-C Garbage Collection with AutoZone (libAuto)

Starting in Mac OS X 10.5 we got automatic memory management on Mac OS X with AutoZone (aka libAuto) with 2 collection modes generational and full. Starting in Mac OS X 10.6 we got an additional mode called local. Garbage Collection works on an entirely different principal than retain count. Essentially what you are doing in garbage collection mode (gc) is trading a little bit of cpu time for the sake of letting libauto collect objects that are out of scope and no longer referenced. At this time garbage collection is only available on the Mac. There has been speculation on when it might be made available on iOS, but I suspect that it'll only become available once the low end of all supported iOS devices are running at least the Apple A4 chip, which means the iPhone 3G and iPhone 3GS would all need to be phased out before this is feasible.
Apple has described AutoZone as
"libauto is a scanning, conservative, generational, multi-threaded garbage collector. "
This means several things. The basic principal of libauto is that from time to time it will scan the memory in use by your garbage collected (gc) app and collect out of scope memory. It is conservative in that Apple has said that when big events (like a user begins typing, massive cpu starts going on, etc.) libauto will just back out and stop collecting rather than possibly slow your application down during critical events. The generational part of this is actually how libauto began scanning your app when version 1.0 came out in leopard, it had 2 modes generational (intended to run frequently) and full (slower and to be run less frequently than generational) and now in 10.6 Snow Leopard we have local. I'll go into how these modes work later on. LibAuto is also language agnostic, it is not intended to just work with Objective-C & C, it is also in use in Ruby via MacRuby right now. Additionally libAuto is open source you can browse the source code from here http://opensource.apple.com/source/libauto/libauto-141.2/ and download a zip file from http://opensource.apple.com/release/mac-os-x-1065/.

Garbage collection is nothing new. Many other programming languages such as Ruby, Javascript, Python & Java have had garbage collection for a long time now, but no 2 garbage collectors work exactly the same. When we go into using garbage collection suddenly having to remember your retain & release messages become a thing of the past, instead you become concerned with having references to all objects you need and if those references are strong or weak. Many people have asserted that the same apps under garbage collection are generally less crash prone. Many apps already use Garbage Collection such as Xcode, Interface Builder, Mac OS X System Apps, Rapidweaver, etc..

How libAuto works

libAuto works on a fairly easy concept, at various points during your applications run on a background thread it will scan your applications memory for out of scope memory and collect what it can. You can think of it on a simple level like so
gc-diagram-1.png
We have an application with many points of memory allocated and some that have been allocated, but are no longer referenced by anything. Additionally I put in a weak reference in this diagram which I will go into more detail soon. What libAuto does is scan your application for root objects and then follows the strong references from those objects to all the other objects it can reach. When it's done it knows all the objects that are reachable from the root objects in the application and marks all the non reachable objects for collection. LibAuto then comes in and collects them. It has 3 modes it works in when scanning your memory and collecting objects.

Generational Mode
This is the mode that was used most often on Leopard. It works on the assumption that most objects are temporary and die young, and so the collector will try and focus on the young objects and not the long lived older objects in the app which have less likelihood of needing to be collected.

[NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehavior10_4];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:dateFormat];
NSDate *returnedDate = [formatter dateFromString:dateString];

return returnedDate;

In this example the purpose of this code is to return a NSDate object. However in the process we create and allocate a NSDateFormatter object. The DateFormatter object is only there temporarily for the purposes of being able to set a attribute on it and then have it create another object from that (our NSDate object) and then we basically just ditch the NSDateFormatter object. When the garbage collector comes along it will notice that the NSDateFomatter was allocated and collect it. You probably do this a lot in your code, basically creating temporary objects in the process of accomplishing the task you are trying to achieve.


Full Mode
Full mode pretty much works as you would expect, it runs through all memory on your application and does a thorough collection. It takes the longest amount of time and so therefore doesn't run as often compared to the other modes.
Up until 10.6 these were the only 2 modes in libAuto. In 10.6 we gained a new mode called local.


Local
local mode works on an entirely different principle than the other 2 modes shown so far. This mode only scans 1 threads stack for variables between 1-96 bytes which is supposed to account for a majority of the objects in use according to Apple. Because it's not scanning your whole app and is only focusing on 1 thread it is much quicker than the other 2 modes. It will not scan Core Foundation objects which have a retain count of 1, you'll need to do a CFRelease on Core Foundation objects to make them eligible for collection.

Working with the Garbage Collector

Now we have a basic understanding of how the garbage collector works, but there are some things we still need to examine before we really have a full understanding of how to work with the garbage collector.


How to trigger the Garbage Collector
The garbage collector class is NSGarbageCollector. The 2 most common methods you will probably use are -collectIfNeeded and -collectExhaustively. The idea is that you being the architect of the app you are working on, know the best points when your application is running to trigger the collector. So for instance you may trigger a bunch of code to be run on startup in -awakeFromNib and you know 1 or a few possible points at which the arc of events in the apps startup will end and at those points you may wish to signal to the garbage collector that you have good points at which nothing is going on and the garbage collector can go through your app and collect memory.

-collectIfNeeded - Use this to suggest to the garbage collector that now is a good time to go and collect memory in the application
-collectExhaustively - Use this to force the garbage collector to collect memory in the application

Again even though you may suggest to the garbage collector that it should collect memory it may at anytime stop collection because of things like the user beginning to interact with your application.


Foundation Tools
In Cocoa apps the garbage collector thread is automatically started for you. However in foundation tools you need to manually start up the garbage collector by calling objc_startCollectorThread(). You can also use the method objc_collect(OBJC_COLLECT_IF_NEEDED) to trigger the collector. Apple also suggests if you do this that you call objc_clear_stack() to make sure nothing is falsely rooted on the stack when doing foundation tools.


__weak
The __weak qualifier is needed to solve a very important problem. If you have 2 objects pointing to each other and at least 1 of those objects has a strong reference to it, then those 2 objects will never go away because as far as the garbage collector is concerned they are reachable through root objects & strong references and therefore not eligible for collection. By default all references are strong references so simply having a pointer to other objects makes them visible to the garbage collector and thus not eligible for collection.
Screen shot 2010-12-22 at 2.06.47 PM.png
These are both objects which have valid strong pointer references. The 2nd window may have had another object reference it at some point in time but that object stopped referencing it and now you have a pointer to it, but you don't necessarily need to keep that reference alive. __weak solves this by allowing you to still have a pointer to the object, but qualifying it with weak so it just nils out when it goes away
gc_windows2.png
this way with weak references the 2nd window becomes eligible for garbage collection, you still have a reference to that object, and when you try and send messages to it they just go to nil  and if you check that pointer you'll see it points to nil assuming it has been collected. This has other benefits, in Mac OS X 10.6 and later NSNotificationCenter is weak referenced so you no longer need do to the following in your code

[[NSNotificationCenter defaultCenter] removeObserver:self
      name:kObservationName
      object:nil];

that's right since notifications are weak referenced you no longer need to remove yourself as an observer from them under garbage collection.


NSMapTable & NSHashTable
Under garbage collection all references to objects are considered to be strong by default. As a result of this you have to either explicitly make references weak by using __weak or by using a class specifically configured to use weak references. These classes include NSHashTable which is a class modeled after NSSet to support weak references, or NSMapTable which has been modeled after NSDictionary to support weak references.


Say goodbye to -dealloc, Say hello to -finalize
Under garbage collection the garbage collector will send the -finalize message to objects instead of -dealloc when collecting them. Most of the time this may not even be necessary to implement this as you will mainly just need -finalize for letting go of external resources like say closing files. In much the same way you'll call [super dealloc] at the end of -dealloc you will also need to call [super finalize] if you need to implement finalize. Additionally your finalize methods need to be thread-safe.
-(void)finalize
{
 if(myFileRef != NULL) {
  //close file
 }
 [super finalize]; 
} 
Making malloc'd memory collectable
There are times when you need to manually allocate memory through malloc or other such functions. Unfortunately the garbage collector does not automatically pick up on memory allocated like this. In order to remedy this Apple has provided the function NSAllocateCollectable().


Core Foundation & Garbage Collection
There are times when you need to dig down into Core Foundation to get functionality not found in the Cocoa Frameworks. As such Core Foundation will have to work with and interact with the garbage collector in gc apps. Luckly when allocating Core Founation objects when specifying the collector if you provide NULL, kCFAllocatorDefault or kCFAllocatorSystemDefault those all allocate memory from the garbage collection zone. In fact by default all Core Foundation Objects allocate from the garbage collection zone.

With Core Foundation any objects you allocate need to be either be released with CFRelease or CFMakeCollectable. Personally I use CFMakeCollectable as I think it makes the intent of the code more clear. Technically speaking CFRelease and CFMakeCollectable are nearly identical, if you do another CFRetain on a Core Foundation object you will need to use a CFRelease or CFMakeCollectable to balance it out. If you are writing code to run on both it'd be pretty easy to check for which one you need to do by checking to see if [NSGarbage collector defaultCollector] is NULL, otherwise CFMakeCollectable is just a no-op in a retain/release environment.
if ([NSGarbageCollector defaultCollector] == NULL) CFRelease(myCFString)


How do I turn this on in my projects?
Garbage Collection is currently only available on Mac OS X projects and not available on iOS yet. To turn on garbage collection in your application you need to open your project settings and search for garbage collection
gc_setting.png
There are 3 possible values you can have for your application.
(1) No GC Flag - Garbage Collection is not supported
(2) -fobjc-gc-only - When compiling with this set, Garbage Collection is required. If you have some bit of code in an external project that is gc only and try to use it in a project that does not support GC then you will get linker errors
(3) -fobjc-gc - When compiling with this both Garbage Collection code and traditional Retain/Release code is generated and the code can be loaded into any app. You probably will not compile apps with this setting and instead use this for Frameworks.
Typically you'll make your Apps support garbage collection or not, and your frameworks will be built with in supported mode (generating both gc and retain/release code.)


A note on Debugging GC
When using the heapshot in instruments you should set the environment variable AUTO_USE_TLC = NO because unfortunately the heapshot feature and the GC Thread Local collector don't work well together. Otherwise the heapshot feature in instruments will think you have more memory allocated than you really do. This and other GC environment variables are mentioned in the famous Mac OS X Debugging Magic Tech Note.
Instruments also contains a great instrument to show you when, for how long and how much the collector collected at various points in your application. If you are writing any gc code it would be to your advantage to run this every so often and get a feel for when the collector is running and what modes it is running in.
gc_modes.png

Conclusion

Managing memory in Objective-C is not nearly as hard as anybody would make it out to be. It's merely a matter of knowing the few memory management rules and periodically running Instruments on on your app, and the clang static analyzer in Xcode to eliminate memory issues. Garbage Collection eliminates many of the issues associated with manual objective-c retain/release, but you still have to know a few rules and how the collector works.

Releated Reading

Mac OS X Debugging Magic Tech Note
Memory Management Programming Guide
Garbage Collection Programming Guide
Instruments User Guide

Wednesday, November 17, 2010

OmniWeb as a Cocoa Documentation Browser

The built in Xcode Documentation browser is okay, and the stuff Apple does to bring some bits of documentation lookup into the code in IDE is not bad. However, until the full documentation browser is it's own app, I don't think it'll ever reach its full potential. One day I saw Peter Hosey use OmniWeb and do a brief run through of what he did to browse documentation.

Since then, I've only made a couple tweaks to this, but I am surprised more people don't use a standalone documentation browser app like this because it's so easy to separate from Xcode and command tab over to and find what your looking for fast.

Download OmniWeb ( http://www.omnigroup.com/products/omniweb/ )

Here are some of the links I have (you'll need to drag them to your bookmarks bar for them to work)

Foundation
AppKit
Core Foundation
Developer Tools
Core Graphics
Core Services
What's New in Mac OS X 10.6 Notes

My Doc/Code Search Templates

ADC Search (Keyword: adc@) http://developer.apple.com/search/index.php?Search=%@
Google ADC Search (Keyword: gadc@) http://www.google.com/search?q=%@+site:developer.apple.com
GoogleCode Search (Keyword: gc@) http://google.com/codesearch?q=%@&hl=en&btnG=Search+Code

Sunday, September 05, 2010

Cocoa Unbound

Mike Ash recently complained about the restrictions on the Cocoa-Dev Mailing list. There are also many things people would like to discuss that Apple just doesn't allow (as part of their policy) on their mailing lists. So Brent Simmons created the Cocoa Unbound mailing list where developers can discuss items that Apple doesn't allow on their mailing lists. Go & join up and have happy sane un(Apple)moderated discussions.

Wednesday, August 11, 2010

Enumerating Lines Concurrently using a Block

Recently on twitter I asked about enumerating over the lines of a string concurrently using a block. I couldn't see an API to deal with this issue directly. If you look through the Mac OS X 10.6 SDK you'll see this

- (void)enumerateLinesUsingBlock:(void (^)(NSString *line, BOOL *stop))block
Which is a synchronous operation processing each line ( the components separated by \n ) one by one until you've gone through the whole thing. However, this doesn't work if you want to go through the lines concurrently, but make the operation as a whole (not proceeding on until all the lines have been processed) synchronous. Steve Streza came up with a solution that I should have thought of, but didn't seem obvious at the time till I saw the solution.
[[myString componentsSeparatedByString:@"\n"] enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
   NSString *line = (NSString *)obj;
   //do what your going to do with line...
A minor hack, but it works and isn't incredibly inconvenient. Still I wish Apple would make this API
- (void)enumerateLinesWithOptions:(NSStringEnumerationOptions)option usingBlock:(void (^)(NSString *line, BOOL *stop))block
[myString enumerateLinesWithOptions:NSEnumerationConcurrent usingBlock:^(NSString *line, BOOL *stop){
 //do stuff with the line...
I was also asked why I didn't do something like
[stringArray enumateLinesUsingBlock:^{ dispatch_async(myQueue, ^{
And the reason is simple, while that would technically work, i'd not know when the operation as a whole was completed. You would really want to use a dispatch_group so you could dispatch all the blocks and then get notified when they are all completed. However the solution above works with a minimal of fuss and the operation as a whole is synchronous while the line processing is asynchronous. We could do the same thing other ways, but overall we'd be writing a lot more code for really no benefit.

Wednesday, June 09, 2010

Good User Interface Design on Mac OS X and the iPhone OS

Good user interface design can make or break your application, it's not just visual appearance but workflow & accessibility. An application that is visually appealing but not well designed will lose out to an application that isn't as visually appealing but has a well designed user interface.

I am not even going to be able to write as much as I'd like here on the topic of UI design, because to be frank this material could fill reams & reams of paper and still have a lot left to say. So I want to point out some do's, some do nots & just some general Mac OS X & iPhone OS tips I presented at a DM Cocoaheads meeting.

Primary / Secondary / Tertiary Objects

One way of starting out in designing a good UI I heard was to start out and just sit at a white board and write down all the objects in your application. So if we were to take iTunes we could start out with the obvious: Songs, Artists, Playlists, Albums, Videos, etc.

Then break that list up into the primary, secondary and tertiary objects categories. Now look at your primary objects category, those objects should take up most of the UI. You can see this already in just about any great app. In iTunes songs are definitely the primary object and so take up the biggest chunk of the UI. In web browsers the web page is the primary object and thus takes up the overwhelming majority of the UI, in fact every bit of UI on web browsers like Google Chrome or Safari are pretty much just to help you navigate to other webpages in 1 form or another.

googlechrome.png

You can see this sectioning done very well on iTunes as well...

itunes.png

iPhone UI Design / Emphasizing elements through Contrast

Due to the contained space inherent to iPhone Applications you cannot follow some design ideals that Mac Developers follow. For the iPhone it's more about designing your application from a hierarchical design and making any one function not take too long to get to. There are many examples of this I could point to, instead of the usual twitter clients (which also display this well) I am going to show off one of the tools I use to practice Japanese text called iKana Touch.

iKana touch is a very well designed iphone application in that it visually looks great, has a very clear hierarchy of functions and visually emphasizes important elements very well.

IMG_0135.PNG

IMG_0137.PNG

IMG_0144.PNG

 

For me you can't get much simpler than this. You have a Very simple startup menu showing you very well defined groups of Kana glyphs you want to study, the table row items have icons on them that well represent what their section is about and make perfect sense (at least if you are studying Japanese.) This very well represents a phrase I once heard at WWDC "a screenful of UI at a time." This UI section I shown above also is very similar to a UI design pattern I'll show later I call General->Specific where you start out broad, dive in 1 level and see a bit more and then can dive in 1 more level and get to a very detailed level.

I want to show you just a couple more screen grabs to emphasize a couple points.

IMG_0139.PNG

This is iKana Touch's speed test. It's very well designed for several reasons

(1) Anybody can come up and look at this screen and see that this is a speed test and see that there are buttons along the bottom and there is a big kana glyph front and center of the screen which is the glyph that needs to be identified, it's intent is very clear and needs no explanation of what needs to be done.

(2) Colors emphasize important elements well. The timer bar eventually goes red as you have less and less time. If you get an answer wrong it colors the correct answer green and all the other buttons red which imediately draws your attention to the correct answer so you learn.

(3) Although you can't tell here, sounds play an important part the sound you get when you select a correct answer is nice and you get a nice BUZZZZ!!! when you have a wrong answer

At the end of this test you get a nice screen showing you how well you did and the expression on Person's face who shows you your percentage changes depending on how well you did.

Here is another well designed screen...

IMG_0141.PNG

This requires a tiny explanation for those of you who don't know Japanese. The Kana (native Japanese text) & Kanji (Chinese Characters used in Japanese + some native Japanese invented ones) all have stroke orders. One aspect of learning these glyphs is that you need to learn the proper order in which to draw them.

This screen here is to help you learn the proper order in which to stroke the glyph. Again it requires little explanation, it's obvious that there are circles where you need to start and end your points. And to give you the feel of a genuine learning experience the board is chalkboard themed which we associate with school/college and learning. Very well designed, screen. This brings me to the next point. On this application when you hit the detail for each glyph (see the "Nu" card earlier in this article) the application designers went above and beyond (which you should always try to do) and provided animations when you flip the card over...

IMG_0145.PNG

Again just wonderful experience, and a wonderful way to teach people the proper way to stroke each glyph and they are fully taking advantage of iPhone OS (now iOS) technologies to make this a great learning experience. Clearly they've gone out of their way to not only test you well, but help you learn just as good as they test you. And another thing to note is how little UI elements are on each screen (which I appreciate.) It makes the app and experience of using it a pleasant and focused one.

General to Specific Design pattern

Above in the first screens of the iPhone app iKana touch I showed 3 screens revealing more and more detail as you dove down a level in the app. What you may or may not realize is that this is a design pattern from the desktop adapted into the iPhone.

Screen shot 2010-06-09 at 2.20.17 PM.png

Here a great example is one thing many people have seen when they come to the Mac is Delicious Library 2. You can see going left to right across the application that we get an increased level of detail. This makes navigation in the app very simple and your eye knows exactly where to go especially so since I've heard that we tend to scan from the top left to the bottom right. Again there isn't that many UI elements on this screen and the ones that are on there are organized well in their own third of the screen so you know exactly what they are associated with and that (in combination with the icons) makes it easy to know what a controls purpose is.

Android: Mobile Design done wrong

Now before I go on I should state that I both admire some aspects of Android and yet also despise some UI's. To me many Android apps I've seen demonstrate that these developers don't get mobile development in general. With such a constrained UI you can't afford to pile on all the things that you would do in a desktop environment. Let me show you

3869462715_d756e8275b.jpg

Clearly you can see here that we don't have the space available like we did on the desktop to really show everything going on. Although this looks decent for showing you when you have events going on during the week, it's absolutely horrible at displaying any level of detail about the items. Worse i've seen many Android calendar apps attempt to show a bar representing the day and then fill in parts of the bar where they have things going on for the day. It's a good idea in theory, except within the confined screens android devices run on it doesn't look good at all. Generally Android applications are not a good source of UI inspiration. As always though there are some Android apps that have been well designed such as shown by Sebastian on his blog http://blog.cocoia.com/2010/doubletwist-android-media-player-app/

Conclusion

Clearly there are a lot of great things going on in both Mac OS X and iPhone/iPad application UI design. Start out by defining the mission of your app in a sentence. Then sit down and just write all the objects that are represented within your application. Your applications UI should be dedicated to the primary elements and you should try to make sure that anything on screen is there for the purpose of making interacting with the primary objects easier. Also well designed graphics in combination with well thought out workflows in an application can lead to less need to explain the user interface to the user and thus lead to less support and happier users. For iPhone applications you need to think of the hierarchy of your application and it's functions and make sure that the functions that users would most commonly want to perform within your app are easy to get to within a couple taps on screen (or less if that's feasible.)

CC Images

http://farm4.static.flickr.com/3436/3869462715_d756e8275b.jpg

Sunday, April 04, 2010

DM CocoaHeads: Good User Interface Design in Cocoa & Cocoa Touch

http://cocoaheads.org/us/DesMoinesIowa/index.html Thursday, April 8 at 7 pm at the Impromptu Studio in Des Moines,IA (see link above for Map & directions) I recently became the group leader of the Des Moines CocoaHeads, and to get the ball rolling I will be giving a presentation this week on Good User Interface Design in Cocoa & Touch. I thought this would be a good time to do this as several people are starting work on new projects. Some things I'll Cover...

  • Good & Bad User Interfaces and what makes them good and bad
  • How to plan out a User Interface (we'll go through an example test app)
  • UI Design patterns on the Mac and iPhone (and iPad to the extent possible)
  • Q&A/Discussion on UI Design patterns
If your coming feel free to bring your apps in and we can give your UI a good review and help you improve it. Sometime after this is over i'll take my presentation & post it online here via article or screencast, so keep tuned.

Monday, February 01, 2010

The PubSub Framework: Using RSS Feeds in your App

FeedViewer.png
The Project Page for this articles project is on github at http://github.com/Machx/FeedViewer you can grab the source code with git by entering the following command in terminal....
git clone git://github.com/Machx/FeedViewer.git
The PubSub Framework is one of those lesser known Frameworks that Apple introduced in Leopard. It has the ability to parse RSS & ATOM feeds and automatically generate KVO compliant Objective-C objects which you can inspect & enumerate through in your Application. You can even get access to Safari's or Mail.apps RSS feeds and display them in your application. Recently on StackOverflow someone was complaining that there really wasn't an example project showing how you can use PubSub. So what i've decided to do here is setup a minimal project showing how you can efficiently use PubSub to retrieve and display a RSS feed and its contents. I tried to use a bare minimum of custom objects and instead rely on PubSub's classes to automatically generate the objects that should be displayed in the view part of the app, this way you write less code and can more easily extend the code to fit your needs in your own application. I should note that in this example I've decided to take full advantage of Grand Central Dispatch and a 10.6 only API. Here my intent is to take you through a semi-tutorial to show you what you need to do to setup this project. So let's start building this app... First Create a new Cocoa Application Project in Xcode and call it FeedViewer or whatever you want to call it
Snap.png
The next obvious thing we need to do is add the PubSub framework to our app, so right click on Frameworks->Linked Frameworks and go to Add->Existing Frameworks. Find PubSub.Framework and add it. Now create a new Cocoa class which will be our App Controller. Add the following ivars & methods in the header file.
#import <Cocoa/Cocoa.h>
#import <PubSub/PubSub.h>
 
@interface AppController : NSObject {
	PSFeed * newsFeed;
	NSOperationQueue *rssQueue;
	NSError *feedError;
	id psNotification;
}
@property(retain) NSOperationQueue *rssQueue;
@property(retain) PSFeed *newsFeed;
@property(retain) NSError *feedError;
@property(retain) id psNotification;
-(IBAction)startFeedRefresh:(id)sender;
@end
The PSFeed *newsFeed; will both contain information about our RSS Feed and contain the RSS entries once we've started a refresh. The NSOperationQueue *rssQueue; is technically unnecessary here, but to reduce the overall code Im going to use a bit of Grand Central Dispatch + Cocoa magic and a 10.6 only API which let's us register for a Notification & execute a block on another thread from NSOperationQueue. Thanks to the 10.6 API's this is pretty easy & should be done in the background to not interrupt the main UI thread. You could accomplish the same thing on 10.5, but you'd still need an NSOperationQueue, and you'd have to register for a notification on PSFeed and when you see a feed is done refreshing create an NSOperation subclass object, put it on the queue and (again) check for when the NSOperation object is finished executing. The NSError *feedError; is for presenting an error to our users so they have some feedback in the case something goes wrong.The Method -(IBAction)startFeedRefresh:(id)sender; is the only method we really need here for starting the refresh on the PSFeed. Lastly the id psNotification will be used to retain an object that Cocoa gives us for receiving notifications, you'll understand this more later on. In AppController.m i'll explain things slightly out of order just so you know the flow of the code. First the obvious -init stuff...
@synthesize rssQueue;
@synthesize newsFeed;
@synthesize feedError;
@synthesize psNotification;
 
-(id)init
{
	if (self = [super init]) {
		NSURL *feedURL = [NSURL URLWithString:kAppleRSSNewsFeed];
		newsFeed = [[PSFeed alloc] initWithURL:feedURL];
		rssQueue = [[NSOperationQueue alloc] init];
		[rssQueue setName:@"com.FeedViewer.rssQueue"];
		feedError = nil;
		psNotification = nil;
	}
	return self;
}
Most of this doesn't need explanation except for 2 things. First if you've never seen [rssQueue setName:@"com.FeedViewer.rssQueue"]; you should. In 10.6 Apple rewrote NSOperation and NSOperationQueue so they now use Grand Central Dispatch, essentially an Objective-C wrapper around the lower level GCD API's. Plus NSOperation(Queue) provides some nice additional functionality, and it a great fit for how to do threading in Objective-C (See my article on Grand Central Dispatch if you want more info.) Grand Central Dispatch uses Queues as its primary means of receiving blocks to take in and dispatch threads. And for debugging purposes its nice to set a name for these queues so you know which Queues are yours and what the queues are doing. You can name your Queues what you want, but Apple encourages reverse style DNS naming like above. The other thing is I am using here is a constant kAppleRSSNewsFeed which is defined as
static NSString * const kAppleRSSNewsFeed = @"http://images.apple.com/main/rss/hotnews/hotnews.rss";
This could have been accomplished by using #define as well, but I am generally a fan of doing it this way so it doesn't clutter your method list in Xcode with a bunch of #defines that you don't care about most of the time. Now for our -(IBAction)startFeedRefresh:(id)sender method...
-(IBAction)startFeedRefresh:(id)sender;
{
	[newsFeed refresh:&feedError];
}
That's it! This -refresh method is asynchronous (which Apple encourages), so most of the work is done elsewhere. In this case in the -awakeFromNib method...
-(void)awakeFromNib
{
	NSNotificationCenter *notifyCenter = [NSNotificationCenter defaultCenter];
	self.psNotification = [notifyCenter addObserverForName:PSFeedRefreshingNotification 
		object:newsFeed 
		queue:rssQueue 
		usingBlock:^(NSNotification *arg1) {
 
		if ([newsFeed isRefreshing]) {
			return;
		}
		 
		[[NSOperationQueue mainQueue] addOperationWithBlock:^{
			
			if (nil != feedError) {
				[NSApp presentError:feedError];
				return;
			}
			
			//inform our KVO Controllers that we now have 
			//RSS entries to display
			[self willChangeValueForKey:@"newsFeed"];
			[self didChangeValueForKey:@"newsFeed"];
		}];
	}];
}
First off I apologize for how bad the formatting of the first few lines of code look in this method, here on this blog, I am trying to not make the code stretch out horizontally for too long. Anyway all we are doing here is registering for a notification on the (PSFeed *) newsFeed object for the PSFeedRefreshingNotification notification. Also we are giving it a NSOperationQueue object (our rssQueue), and a block to execute. This API is equivalent to registering for the notification and inside -observeValueForKeyPath:ofObject:change:context: we created an NSOperation object and then added it to a NSOperationQueue, instead we are doing this and registering for the notification all with 1 API. It still feels odd assigning a value to -addObserver... especially since if you've been doing this in 10.4 and 10.5 this method has a void return type ( - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context.) However you need to retain this id object given to you, otherwise you'll leak in non-Garbage Collected code and your block will never be called under Garbage Collection, I presume because its being collected by the Garbage Collector before the notification is ever sent out. The first thing we need to do right away is to check if the feed is still refreshing, if it is then there is no point in doing anything else except immediately returning. If we aren't refreshing anymore then the PSFeed is done refreshing and we can then go back to the main thread and send out any notifications, etc to finish up the process. In this case all that needs to be done is sending KVO notifications that PSFeed has changed and that any controller objects that are doing bindings work for us, should update themselves. This is all that is necessary on the code side of things, the rest will be done in KVO with Cocoa Bindings in the XIB. All we need for this is 2 controllers a NSArrayController to bind to the PSFeeds entries array and a NSObjectController to bind to the selected PSEntry object's content object which is a PSContent object. I've created a quick and short video explaining what's going on... So now you understand what's going on in the UI. To give an overview of the entire app this is what happens. We tell our PSFeed objet to refresh its entires. When we receive PubSub's notification, a check is done to see if we are refreshing, if we are then we immediately return, if not then we send KVO notifications to let our bindings controllers update. Our NSArrayController updates and our NSTableColumns which are bound to NSArrayController update and populate the table. When the Table has a selection our NSObjectController updates with the PSContent object and a NSTextView which binds to the plainTextString property updates and displays the content for the selected PSEntry object. Here are some useful links Publication Subscription Programming Guide Publication Subscription Framework Reference Short and Sweet. Now get using RSS in your apps!

 
...