Cocoa with Love

Advanced programming tips, tricks and hacks for Mac development in C/Objective-C and Cocoa.

The design of an iPhone application

In this post, I'll discuss iPhone program design using the example of a small but non-trivial iPhone application to provide examples of how the design is implemented. The design includes: how to manage data coming from different sources, how to manage multiple views of that data and how to design your program so it remains simple and manageable as it grows. In short, I'll be discussing how Model-View-Controller (MVC) applies to an iPhone application but I'll also discuss how even simple programs are considerably more hierarchic through their controllers and branched through their models and views than the basic description "Model-View-Controller" might imply.

The sample program

The sample program for this post takes the Core Data SQL database of Australian Postcodes that I created last week from a CSV file and uses that in an iPhone application that allows you to:

  • Browse and search the database.
  • Display entries in a MKMapView.
  • Find the nearest entry to the user's GPS and display that on a map.

The following screenshots show the basic flow of the application.

IMG_0018.PNG IMG_0020.PNG IMG_0021.PNG

The "Show current location" step skips the middle screenshot in the workflow and goes straight to the map, displaying the closest "Postcode" in the database for the user's location, or just the user's location (with no pins in the map) if they are more than 0.1 longitude or latitude away from the nearest post office.

You can download the complete project AustralianPostcodes.zip (961kB).

Steps in designing a program

The basic steps in designing a small user program are:

  1. Decide what the program will display to the user.
  2. Work out how the user will navigate through the program to reach each view.
  3. Work out the data that is needed to populate the views that the user will navigate.
  4. Decide where that data will come from and how you will manage access to it.
  5. Decide how and when you will construct your views.
  6. Decide how you will provide your views with data.

The first two points are the program's requirements and the remainder is the high level design. For this post, I'm going to consider the first two points complete (as given in the previous section).

I'll discuss steps 3 and 4 as a single concept "Program data", then steps 5 and 6 as "Program construction".

Program data

While it might not be obvious, this program actually has 3 different sources of data:

  • Postcodes and their related data
  • The GPS location
  • The cache of fetched postcodes, filtered by search terms
  • The cache of postcodes nearest the selected location or GPS location
  • List of menu items on the top-level page

The last item doesn't need to be data (it could easily be done in code) but I wanted to talk about a range of different data sources and implementing menus like this from data can dramatically reduce the size and complexity of your code (see my earlier post Simplifying your code using NSDictionary).

Postcode data and the PostcodeController

Obviously in this program, the Core Data SQL database is the source of the postcode data. However, there is more to clarifying the data source than that.

The postcode data is used from multiple views in the application. For this reason, it will need to live in its own persistent location that views can access when needed. To handle its creation, persistence and access, we'll need some form of controller to manage the lifecycle of this data and access to it.

Core Data runs in an NSManagedObjectContext. In some respects, you may consider that the NSManagedObjectContext manages access to the data. While this is true at the low level of reading, writing, cacheing and fetching, the reality is that NSManagedObjectContext is not a manager in a broader sense for your program and your program specific logic.

Specifically, your program will need:

  • A way to construct the Core Data persistence stack (i.e. open a Core Data SQL store and create an NSManagedObjectContext for it).
  • A way to access the current context from anywhere in the program.
  • A place to put context processing code (if needed). This might include importing/exporting code, specialized fetching code, editing and validating code.

While this iPhone application doesn't need the last point, the first two are necessary.

In the default Xcode template for an iPhone application using Core Data, the NSManagedObjectContext is constructed in the AppDelegate object and from there is pushed onto the RootViewController so that it can be used there.

Simply put: I dislike this approach because it gives the AppDelegate multiple responsibilities unrelated to its primary purpose.

The AppDelegate exists to implement functionality during key points in the UIApplication's lifecycle (most importantly startup and shutdown). The AppDelegate doesn't use the NSManagedObjectContext for itself and the AppDelegate's primary responsibility is not document management — you should not be using your AppDelegate as your application's document manager.

Every class should have a single purpose
Every piece of functionality that a class exposes to the rest of the program (i.e. functionality that is part of the class' external interface) should be obviously part of that class' primary role in the program.

For this reason, I create a class (in this project it is named PostcodesController) whose responsibility it is to construct the document (our NSManagedObjectContext) and handle access to it or process the document if needed.

The PostcodesController will be a singleton, as most document managers are (see the NSDocumentController in Mac OS X). Since the application only has one set of Postcode data, there is no need to select the "current" document or manage a set of Core Data persistence stacks but this class is where that behavior would be added if needed in future.

The PostcodesController is then acccessed by the PostcodesViewController to get the current context. However, the data this context contains is not used directly; it is cached by the NSFetchedResultsController as a separate set of data and from there it is used to populate the table view.

Map data

Map data in the application consists of three parts:

  • The map "tiles" (the street map shown in the view)
  • The "current location" (which is either the result of a selection or the GPS location).
  • The array of pins displayed in the map

The actual map tiles are loaded by the MKMapView that Apple's MapKit provides. We don't really need to worry about that.

The selected location or GPS location is a little trickier. This either comes from the user's selection on a previous screen or from the CLLocationManager (which supplies us with location data from the GPS). If this was used by multiple views in the application, then we would need a special class to manage the current location for the whole application (like the PostcodeController manages the postcode database for the whole application) however, we only need location data on the map screen, so the MapViewController which manages this screen can handle this.

The array of pins displayed on the map is really just a selection of the data from the postcodes database, selected using criteria from the current location. Again, since this is only used on the map screen, so it can be controlled by the MapViewController as long as the difficulty of doing so remains low.

List of menu items

Sometimes, data is so simple to load and so customized to the location where it will be used that managing it is no concern at all. The array of dictionaries that provides the structure for the "Main Menu" in the program is a good example of this — the data can be read in a single instruction, its format is written to match the format that the "Main Menu" wants, it has no state to maintain and doesn't require any editing.

Program construction

This program started with a "Navigation-based application" template in Xcode and the project name "AustralianPostcodes". This means that the following steps are setup by the template:

  1. The UIApplication will load the MainWindow.xib on startup
  2. The MainWindow.xib will construct the AustralianPostcodesAppDelegate, a UIWindow and a UINavigationController which will load the RootViewController from RootViewController.xib and set it as the top level view in the navigation hierarchy.
  3. The AustralianPostcoddesAppDelegate will insert the UINavigationController's view into the UIWindow and display the window.

The primary controllers in the program are the PostcodesController (which controls the construction of the Core Data persistence stack), the RootViewController (which shows the main menu), the PostcodesViewController (which displays the table of objects fetched from Core Data) and the MapViewController (which displays a single Postcode object and the map view).

Constructing the RootViewController

The RootViewController needs to display its list of options in the table. When any row in the table is tapped, a new UIViewController subclass will need to be constructed and pushed onto the UINavigationController.

Due to the data-configured nature of the RootViewController, the subclass of UIViewController constructed and any parameters passed into its initializer are all specified in the data file.

This means that this class is incredibly simple. The three different rows perform three different tasks:

  1. Load a PostcodesViewController and sort by postcode
  2. Load a PostcodesViewController and sort by suburb
  3. Load a MapViewController and use the GPS for location data

But the differences come from the data. The work done by the RootViewController is the same in each case.

Constructing the PostcodesViewController

This class displays the postcode data but it has to perform four tasks as part of that job:

  1. Fetch the sorted (and possibly filtered) postcodes from the database
  2. Construct/configure the table view cells to display the fetched results in the table
  3. Respond to changes in the search string by refetching the data
  4. Respond to taps on a row by loading a MapViewController to display the map

In this case, much of the first step is handled by a standard NSFetchResultsController. This class is designed to work closely with the UITableView so it makes sense to keep this work close to the view. If we weren't using an approach so closely tied to the view, it would also be possible to put a fetch method in the PostcodesController and pass parameters to it so that it prepared the data in an appropriate format.

When a row is selected, the Postcode object (the subclass of NSManagedObject associated with the selected row) is passed into a newly constructed MapViewController.

Constructing the MapViewController

The MapViewController needs to perform the following tasks:

  1. If not given a selected Postcode object, then the Postcode in the database nearest the GPS location must be fetched.
  2. Postcodes around the current location must be fetched and displayed on the map
  3. The map view must be centered on the selected postcode
  4. Details about the selected postcode must be displayed in the UILabels at the top of the screen.

To enable the easy display of postcodes as points on the map, the Postcode class (the subclass of NSManagedObject used by the Postcode entity in the Core Data model) implements the MKAnnotation protocol. This means that the Postcode objects returned from a fetch can be immediately added to the MKMapView.

This class needs to perform its own fetching from the Core Data database. Since the PostcodesViewController and MapViewController both need to fetch (albeit in slightly different ways) and they both use a significant volume of code of to do this fetching, it is possible that a common interface to perform fetch actions for both would be a future improvement.

Always be ready to iteratively refactor
As you implement a program, you should always be on the lookout for easy ways to simplify your program by implementing minor redesigns. Looking for multiple places where your program repeats the same functionality is the most prominent example of this. A corollary to this is that you should never copy and paste blocks of code — a copy and pasted block of code should be a single method/function/macro that you simply invoke from multiple places.

Model-View-Controller

Interpreting this program according to model-view-controller would go like this:

  • Model — the Postcode objects in the NSManagedObjectContext are the model.
  • View — the UITableViewCell objects on the "Main Menu", "By suburb" and "By postcode" screens and the MKMapView on the map screen.
  • Controller — the AustralianPostcodesAppDelegate, RootViewController, PostcodesViewController, MapViewController, PostcodesController.
Why do we need so many controllers?

An interesting point to note is that every class in the project (with the exception of Postcode) is a controller class.

Why do we need so many controllers? The answer is that we have a normal number of controllers — the correct analysis is that we have is an absence of custom model and view objects.

A well written model object or view object needs no custom code for customization — the construction provided by the controller and the data (provided from configuration files on construction or from model objects when loaded) is all the customization that they require.

I've written posts about drawing customizing table views without subclassing any views — the customization comes from how the view is constructed and set up.

On the model side, NSManagedObject is configured by the .xcdatamodel file and can be used without further configuration if desired. Similarly, NSDictionary is used by the RootViewController to hold custom structure data without need for custom behavior.

Obviously you will probably need custom model and view objects at some point but the fewer you have, the easier things will be.

A simple diagram of the program
basicMVC.png

Generally though, I don't like this type of over-simplification. My problem is that while it does describe a single Model-View-Controller path through the program, this program has multiple sources of data and each source of data is managed at a different point and displayed in a different way.

A different way to think about application design

Despite the simplistic diagram shown above, the reality is that we have the following model-controller relationships in the program:

  • The Postcodes in the NSManagedObjectContext, controlled by PostcodesController
  • The Plist which describes the Main Menu, controlled by RootViewController
  • The cached fetch of Postcodes by suburb or postcodes, controlled by NSFetchedResultsController in conjunction with PostcodesViewController
  • The cached fetch of nearest Postcodes, controlled by MapViewController
  • The GPS location, controlled by CLLocationManager

So a full diagram of the data paths through the program would be considerably more complex than the diagram shown above.

An important point to note about the above diagram is that there are two layers of controllers: one layer that controls the model at the top and one layer that controls the views at the bottom. The result of this observation is that the view-and-controller pairs and the the model-and-controller pairs are really two instances of the same design pattern. This means that we can add the following view-controller relationships to the list of model-controller relationships shown above:

  • The UITableViewCells in the UITableViews, controlled by PostcodesViewController and RootViewController
  • The UILabels and the MKMapView, controlled by the MapViewController
Module-controller

What this does is to break the entire program down into pairings of:

  • Class that "does" something (store data, display data, fetch data)
  • and Controller which loads and configures it

Your program is then a hierarchy of controllers (UIApplication/AppDelegate, Document controller, UIViewController subclasses) which load and configure their own modules (.xib files and windows, Core Data, UIView classes) to perform their actual work — but these modules have no connections to the rest of the program, they rely entirely on the controller to set them up, provide their data and make them work.

As your program grows larger and more complex, your controllers may have sub-controllers — in fact, your module objects may become controllers to their own sub-module objects. Through this structure, you can have a giant program but each element is still simple within itself. Simplicity remains as the program grows because every individual element is self-contained.

Implications of this way of thinking
The best programs are highly modular and decoupled
A good application has tightly focussed modules which are totally decoupled from the rest of the program and controllers which are lightly coupled to other controllers in a hierarchical arrangement through the program but do nothing other than provide the contextual information for their controlled objects.

The idea is to make all aspects of your program clean, decoupled and resusable, in the same way that good view and model classes are.

I prefer this way of thinking about application design. In essence, treat every data object, every network connection and every view object in the program (any class which "does" something) in the same way: like its own independent module. These independent module classes should:

  • have their own controller which loads and configures them
  • not have a connection (pointer or reference) to any other part of the program (except other objects within the module)

If you feel like one of these module objects needs to access another part of the program, try to redesign so that the controller pushes the information to the modular class, instead of the module object fetching for itself.

The corollary to this is that your controller objects should, as much as possible, avoid "doing" anything except constructing and configuring these document-like objects. Controllers may have a lot of code compared to the module classes but that code should always be responding to a change from a module object and passing a message to another module or constructing another module. Controllers are all about setup, reactions and inter-module communication.

Most of the time, the module objects controlled by the controller will not be your own special subclasses — often they're just default NSDictionary objects or UIViews or NSManagedObjects — but it is important to keep the module object and controller relationship in mind to help guide how you write your program.

Keep the main advantage of Model-View-Controller thinking

Even if you do start thinking about every component in your program in module-controller terms, you shouldn't drop the key advantage of Model-View-Controller — to focus your application around the workflow of your "model".

Specifically: you should always know what the "model" of your program is. All aspects of your program should be directed towards showing, editing, displaying that data. Even if lots of other modules, tasks and activities are implemented as part of the overall process, they should not disrupt the model's workflow.

Conclusion

You can download the complete project AustralianPostcodes.zip (961kB).

I wrote a lot of code for this post but I've included none of it here. The code exists to make the abstract discussion about how to design a program seem less abstract — I hope that you can look at the code and understand the sometimes vague statements I've made in this post.

The first half of the post was about identifying the data your program has and then identifying how to build the controllers in your program to load and display this data. The purpose of going through these steps is to explain that these are the details you must have clear in your mind before you start writing code. Programming requires — above all else — that you be able to absolutely and unambiguously clarify your idea.

The second half of the post was about module-controller relationships. The purpose here is not to say Model-View-Controller is wrong but to point out that the purpose of Model-View-Controller is decoupled, reusable modules with all construction and context provided by hierarchy of lightly coupled controller objects running through the spine of your program — and that this is a pattern that can be applied repeatedly (and even recursively) throughout your program, not just to views or your main model.

Read more...

There's a Garbage Collection ninja hiding in the project templates

Not all Xcode project templates are alike. Especially the Core Data Command Line Tool...

An unwanted feature jumped out and attacked me!

In yesterday's post on implementing a CSV parser, I briefly mentioned that the parser took around 0.28 seconds to parse the test data that I provided. I consider this a good time for the parser to take but my first run was not so quick.

The first timing test I ran gave a parsing time of 1.15 seconds. This was slightly shocking to me, since I had already run a "control" test — where I just used componentsSeparatedByString: to break into lines and then into fields — that took just 0.95 seconds.

Had I really spent all that time writing code that was 20% slower (albeit more functional) than a clumsy, brute force approach?

No. As it turns out, the Xcode Project Template I had used for the test project, the:

    Mac OS X→Application→Command Line Tool→Type:Core Data

project has Garbage Collection enabled by default.

The only real hint that this template is different is the objc_startCollectorThread() line in the default main() function — of course, I never saw this line because I always replace the source files in the templates with my own versions that follow my own formatting style.

Anyway, I turned Garbage Collection off and... boom 4 times faster.

I'd ask for more warning about these major — but subtle — changes to templates in the future but you know... ninjas, what can you do?

Read more...

Writing a parser using NSScanner (a CSV parsing example)

Comma-separated value (CSV) files are one of the most commonly used data formats for exchanging rows of simple data. There are many implementations of CSV parsing for Cocoa strings but the purpose of this post is to use the example of an RFC4180 compliant CSV parser implementation to show you the basics of writing a recursive descent parser for importing data into your Cocoa applications.

Introduction

CSV parsers for Cocoa already exist: Drew McCormack at MacResearch has a good article covering his implementation of a CSV parser and cCSVParse will also do the job. Instead of CSV and the implementation itself, I'm going to try and focus on reading a parser grammar and adapting that into a program of your own.

Most common solutions for parsing CSV files involve quick parsers which don't consider the full format and instead just split strings into lines using -[NSString componentsSeparatedByString:@"\n"] and then split lines into columns with -[NSString componentsSeparatedByString:@","]. This will work for some cases but it does not handle all aspects of RFC4180 and is limited to simple CSV files.

The technical description of a CSV file

Adapting slightly from RFC 4180 - Common Format and MIME Type for Comma-Separated Values (CSV) files, the Extended Backus-Naur Format (EBNF) grammar for a CSV file is as follows:

    file = [header lineSeparator] record {lineSeparator record}
    header = name {separator name}
    record = field {separator field}
    name = field
    field = escaped | nonEscaped
    escaped = doubleQuote {textData | separator | lineSeparator | twoDoubleQuotes} doubleQuote
    nonEscaped = textData
    doubleQuote = '"'
    twoDoubleQuotes = '""'
    separator = ','
    lineSeparator = ('\r' | '\n') {'\r' | '\n'}
    textData = {characters up to the next double quote character, separator string or lineSeparator}

If you're not accustomed to reading EBNFs, the very first line here (the "file" line) states that a CSV "file":

  • optionally has a "header", which if used must be followed by a "lineSeparator"
  • must have a "record"
  • the first record may be followed by any number of "lineSeparator" plus "record" entries.

The grammar shown here is slightly less restrictive than RFC4180 in that it allows any data (not just the CSV subset of US-ASCII) in the "textData". I'll also implement the parser so that different separators (including any string that contains no new line or double quote characters) can be used instead of commas. The implementation will also support Unix newlines or classic Mac carriage returns can be used instead of DOS "\r\n" line separators.

Design of the parser

The parser will be a form of recursive descent parser, which is the easiest way to implement most simple grammars like the one above. The idea is that we write a method for each line of the grammar. If any line contains a reference to another line, the implementation method will attempt to descend into the method for the referenced line.

If you're accustomed to the lex/yacc school of thought and are curious to know if the approach will similarly split tokenizing and parsing into separate stages: yes, it will. Most of the tokenizing is done by NSScanner (although it presents each token as requested, not as a pre-prepared stream). The code we actually implement will predominantly deal with the parser/generator side.

Initialization of the parser will be handled by the following method:

- (id)initWithString:(NSString *)csvString
    separator:(NSString *)separatorString
    hasHeader:(BOOL)hasHeader
    fieldNames:(NSArray *)fieldNames;

The structure of CSV files means that it is difficult to guess if the header line is actually present — so we need to tell the parser whether to look for it. An array of names for fields can be provided if there is no header (if no names are provided, they'll be given names with the format "FIELD_X").

The parsing will be initiated by invoking either:

- (NSArray *)arrayOfParsedRows;

where the result is an NSArray of NSDictionary objects or with:

- (void)parseRowsForReceiver:(id)receiver selector:(SEL)receiverSelector;

where the method receiverSelector must take a single NSDictionary parameter. This second method does not return the entire result but instead sends each row as it is parsed to the receiver. It is more efficient since it does not need to keep copies of all row data.

Parser methods

There are two types of parsing methods that we need to implement:

  • Structural methods which don't directly access the string (parseFile, parseHeader, parseRecord, parseName, parseField, parseEscaped, parseNonEscaped)
  • Tokenizing methods which use NSScanner to access the string (parseDoubleQuote, parseTwoDoubleQuotes, parseSeparator, parseLineSeparator, parseTextData)

I'm not going to show all of them here (you can download the full code to see them) but I will show one of each type.

The tokenizing methods are the easiest. All they do is invoke NSScanner methods.

- (NSString *)parseLineSeparator
{
    NSString *matchedNewlines = nil;
    [scanner
        scanCharactersFromSet:[NSCharacterSet newlineCharacterSet]
        intoString:&matchedNewlines;];
    return matchedNewlines;
}

The structural elements have a bit more to do but are still fairly simple. The "escaped" element in the grammar has the following structure:

    doubleQuote {textData | separator | lineSeparator | twoDoubleQuotes} doubleQuote

This structure is directly reflected in its implementation — it starts and ends with a check for "doubleQuote" and loops over checks for "textData", "separator", "lineSeparator" or "twoDoubleQuotes" in the middle.

- (NSString *)parseEscaped
{
    if (![self parseDoubleQuote])
    {
        return nil;
    }
    
    NSString *accumulatedData = [NSString string];
    while (YES)
    {
        NSString *fragment = [self parseTextData];
        if (!fragment)
        {
            fragment = [self parseSeparator];
            if (!fragment)
            {
                fragment = [self parseLineSeparator];
                if (!fragment)
                {
                    if ([self parseTwoDoubleQuotes])
                    {
                        fragment = @"\"";
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
        
        accumulatedData = [accumulatedData stringByAppendingString:fragment];
    }
    
    if (![self parseDoubleQuote])
    {
        return nil;
    }
    
    return accumulatedData;
}

An interesting point to note is that most parsing stages return the text that they parse. However, when parseTwoDoubleQuotes is used, we instead append just one double quote character, since the two double quotes is actually an escape sequence representing one.

Lookaheads

The most annoying feature to implement in a recursive descent parser is a lookahead — this happens in the parseTextData method.

Lookahead is required because of my choice to accept separator strings longer than a single character. This means that the "textData" element will end with any of:

  • \r
  • \n
  • U+0085
  • "
  • the separator string

Unfortunately, NSScanner can't scan until it reaches one of these 5 elements. The best we can do is create a character set from the first four and the first character in the separator string and use scanUpToCharactersFromSet:intoString:

When scanning through text data, if we reach the first character of the separator string, we need to scan ahead and see if it is actually the whole separator string. The whole separator string will terminate the "textData" without being added, otherwise we backtrack and add the character to the existing "textData" and continue scanning.

If NSScanner had a scanUpToStringFromArray:intoString: method, this lookahead could be avoided (or at least shifted out of our code and into NSScanner). But this method does not exist and it looked like too much work to efficiently implement as part of this post.

The sample program

The sample program that I've provided uses this parser to parse a 1.7 MB CSV file containing 16,081 Australian postcode entries, names and longitude/latitudes (data from SixFive.co.uk). As results are parsed, they are entered into a Core Data SQLite file.

The whole process takes about 0.47 seconds on my Mac Pro with parsing taking 0.28 seconds of this time and Core Data object creation taking 0.19 seconds. I'm sure a more carefully coded parser could halve this time or better but it represents good performance for minimal effort.

Conclusion

You can download the CSVParser class and CSVImporter sample project (315kB).

The aim in this post was to present a complete, flexible CSV parser while making the code as easy to read as possible. I hope that it has shown how you can import data from unconventional formats into Cocoa-friendly formats easily while obeying the more minor quirks that many formats have.

The type of parser presented here is a recursive descent parser. This is the easiest parser to implement for simple grammars. However, this is not how commercial parsers are written — larger parsers use generated action and goto tables to handle their branches instead of manually written methods and code. Have a look at the Wikipedia entry on LR parsers for more on how this is done.

Read more...

Performance tests: Replacing Core Data Key Paths

In Mac OS X 10.5, Core Data switched from using valueForKey: as the recommended way to access Core Data attributes and relationships to auto-generated accessor methods. This new approach is faster for fetching values but lacks NSKeyValueCoding's ability to coalesce the values extracted from every object in a "to-many" relationship in a single statement.

In this post, I'll look at replacing the NSSet traversal and NSSet coalescing abilities offered by NSKeyValueCoding with an approach that invokes accessor methods directly to see if I can bring some of the performance improvement of auto-generated accessor methods to situations involving NSSet traversals.

Accessing the attributes and relationships of an NSManagedObject

In this post, I'll look at performance in a Core Data program using the following model:

modelentities.png

If you're not familiar with Core Data entity diagrams, the important point here is that every Company can have multiple Projects and every Project can have multiple Employees

Given this model, if I have a pointer, aCompany, which points to one of the Company objects, getting the company's name is straightforward:

NSString *companyName = aCompany.name;

The name property accessed here is implemented in an auto-generated accessor method that NSManagedObject provides for us.

Before Mac OS X 10.5, the only way of accessing values in Core Data was using key value coding:

NSString *companyName = [aCompany valueForKey:@"name"];

Why was the change away from key value coding made? The main reason was performance (although improved syntax and type-safety also helped). Fetching the name one million times using key value coding takes 0.284016 seconds but using the auto-generated property accessor method this drops to 0.109017 seconds — 2.6 times faster.

Set traversal

But key-value coding (the "old" method) still has one important advantage over the auto-generated methods: it's quicker when traversing a set returned from a 'to-many' relationship.

For example, if I want to get the full set of Project names used by aCompany it is easy with Key Value Coding:

NSSet *projectNames = [aCompany valueForKeyPath:@"projects.name"];

This works because the NSSet implementation of the NSKeyValueCoding protocol automatically traverses into itself to get the names for each Project object it contains.

Using the accessor methods, the naïve equivalent would be:

NSMutableSet *result = [NSMutableSet set];
for (Project *project in aCompany.projects)
{
    NSString *name = project.name;
    if (value)
    {
        [result addObject:value];
    }
}

Not only is this more code than the key value coding approach but it is actually slower. For 10,000 Company objects, each with 100 Project objects, the key value coding approach took 0.25692 seconds and the naïve approach using auto-generated accessors took 0.52873 seconds.

The new and improved approach has gone from 2.6 times faster to 2 times slower.

Fixing the speed problems

The old method got faster

Before I get to why the "new" method was slower, the first point to notice is that the key value coding approach (the "old" approach) was actually faster when using set traversal. Despite the extra work involved in traversing from the Company to the Project and uniquing the names to form a single NSSet, the key value coding took just 0.25692 seconds to fetch one million Project names, down from the 0.284016 seconds to fetch one million Company names.

This isn't a glitch; despite more work involved, Key Value Coding improves its performance when sets are iterated internally (as part of the key path) rather than externally (as I did when iterating over one million Company objects).

Despite its improvements, we should still be able to beat Key Value Coding with our approach using the auto-generated accessor methods but the margin is obviously going to be a lot closer than it was for the aCompany.name iteration..

Fixing the new method

Basic profiling quickly reveals that the problems here have little to do with the actual property accessors. The slow speed is primarily due to addObject:

After looking at the private methods on the stack in the profiler, it became clear that the reason was reallocation. Every time the NSMutableSet needed to grow in size, it was reallocating its internal storage, resulting in the poor performance.

We can pre-allocate the entire set based on the worst-case size (all Project names unique). The code then becomes:

NSSet *projects = aCompany.projects;
NSMutableSet *result = [NSMutableSet setWithCapacity:[projects count]];
for (Project *project in projects)
{
    NSString *name = project.name;
    if (value)
    {
        [result addObject:value];
    }
}

Success! This version now runs in 0.19104 seconds (down from 0.52873 seconds) and is now 25% faster than the key value coding approach.

We're no longer 2.6 times faster but NSSet's internal implementation of Key Value Coding has some advantages over us here: since it has internal access to the storage, it can optimize the iteration over the "to-many" relationship and the building of the new set more than we can.

A category implementation

To reuse the above approach in future, we can implement a category on NSSet.

There will be two methods:

  • objectValuesForProperty:
  • coalescedValuesForProperty:

The first will implement the previously mentioned example (where the NSSet contains basic objects).

The second will replicate the Key Value Coding operator @distinctUnionOfSets (to handle the case where the NSSet contains an NSSet and you need to coalesce the objects inside the child sets).

An example of this second case is getting all the Employee objects at a Company. In Key Value Coding we would write:

NSSet *allEmployees = [aCompany valueForKeyPath:@"[email protected]"];

With the coalescedValuesForProperty: method, we could write:

NSSet *allEmployees = [aCompany.projects coalescedValuesForProperty:@selector(employees)];

The implementation is then:

#import <objc/message.h>

@implementation NSSet (PropertyCoalescing)

- (NSSet *)objectValuesForProperty:(SEL)propertySelector
{
    NSMutableSet *result = [NSMutableSet setWithCapacity:[self count]];
    for (id object in self)
    {
        id value = objc_msgSend(object, propertySelector);
        if (value)
        {
            [result addObject:value];
        }
    }
    return result;
}

- (NSSet *)coalescedValuesForProperty:(SEL)propertySelector
{
    NSInteger count = 0;
    for (id object in self)
    {
        count += [objc_msgSend(object, propertySelector) count];
    }
    NSMutableSet *result = [NSMutableSet setWithCapacity:count];
    for (id object in self)
    {
        id value = objc_msgSend(object, propertySelector);
        if (value)
        {
            [result unionSet:value];
        }
    }
    return result;
}

@end

With the coalescedValuesForProperty: method we iterate over the whole set twice to get the size but this remains the fastest option — in fact, this method is about 35% faster than the Key Value Coding approach compared to objectValuesForProperty:'s 25% improvement.

Conclusion

By request, here's the code used in the testing: PropertyAccessors.zip (32kB). It's hastily thrown together to accompany this post, so it's not necessarily well written but it's there if you're interested.

I wrote this code and ran these performance tests because I have a lot of code that uses Key Value Coding for traversing "to-many" relationships. I was concerned that since Core Data advocates the use of the auto-generated accessor methods for performance reasons, that my use of key value coding in these cases would be significantly slower than it should be.

The result is that while it is possible to improve upon the performance of Key Value Coding for traversing sets in Core Data, the improvement is only 25-35%, not the 260% improvement from replacing Key Value Coding for individual property access. Key Value Coding is quite efficient when dealing with sets — certainly more efficient than it is when accessing single properties.

Of course, the 35% speed improvement offered by the approach presented here will certainly be beneficial in performance critical areas.

With regards to the implementation itself: never underestimate the performance impact of keeping memory reallocations at a minimum. Starting with a zero capacity NSSet and continually growing it using addObject: was 3 times slower than allocating once.

The capacity of the NSMutableSet allocated is large enough to hold all objects but if the objects are not all unique, this will be bigger than required. If this extra memory usage is a concern, you can copy the set once it is generated. The copy will be only as big as strictly required and you can release the original. The drawback is that this copying process will add another 10-15% onto the time taken.

Read more...

A drop-in fix for the problems with NSHost

As pointed out by Mike Ash in his recent Friday Q&A; 2009-11-13: Dangerous Cocoa Calls, NSHost is not thread-safe for use outside of the main thread and due to potentially slow, synchronous network access is not really suitable for use on the main thread either. Fortunately, in Cocoa there are often ways to transparently fix classes that don't work as they should. In this post, I'll show you how you can transparently patch NSHost using a drop-in solution and provide a non-blocking solution for NSHost lookups.

NSHost

NSHost is a class with a simple API that fetches the names or addresses of an internet host. You can use it to perform DNS lookups but one of the primary uses is to get the name and address of the current host.

All calls to NSHost are synchronous — they block until the response is fetched. If a network error occurs, this could result in a 60 second delay before a timeout response occurs — definitely not something you want to do in your main thread.

Unfortunately, according to Cocoa's Thread Safety Summary, NSHost is not thread-safe — so we can't simply pass the functionality off to another thread.

Does this mean you must revert to NSHost's CoreFoundation equivalent, CFHost, which is explicitly thread-safe? Not necessarily.

The problems we need to fix

It is not the NSHost objects themselves that are the problem. NSHost objects are immutable once allocated and immutable objects are implicitly thread-safe for most purposes.

The problem is the cache of NSHost objects maintained internally by NSHost when any of the lookups are called — access to this cache is unprotected from the perils of threading.

In addition to this, we need to be able to perform NSHost lookups asynchronously.

Design of the solution

The key consideration in these changes will be a totally drop-in solution — NSHost will immediately and transparently become thread-safe. No further code will be required.

The solution to the threading problem will be to create a corresponding category method for every class method of NSHost which wraps all calls to NSHost in a @synchronized section and then in the load method for the category, swizzle each of these corresponding methods into the place of the original method.

The asynchronous invocations can then be handled like any other asynchronous operation — by spawning a new thread which will call back when complete.

Swizzling alternate implementations

If you don't know what I meant by "swizzle", what we need to do is replace the existing implementations of the NSHost class methods with our own implementations. The code for doing this is as follows:

static void SwizzleClassMethods(Class class, SEL firstSelector, SEL secondSelector)
{
    Method firstMethod = class_getClassMethod(class, firstSelector);
    Method secondMethod = class_getClassMethod(class, secondSelector);
    if (!firstMethod || !secondMethod)
    {
        NSLog(@"Unable to swizzle class methods for selectors %@ and %@ on class %@",
            NSStringFromSelector(firstSelector),
            NSStringFromSelector(secondSelector),
            NSStringFromClass(class));
        return;
    }
    
    method_exchangeImplementations(firstMethod, secondMethod);
}

Then, in the load method for our category...

@implementation NSHost (ThreadSafety)

+ (void)load
{
    SwizzleClassMethods(self, @selector(currentHost), @selector(threadSafeCurrentHost));
    SwizzleClassMethods(self, @selector(hostWithName:), @selector(threadSafeHostWithName:));
    SwizzleClassMethods(self, @selector(hostWithAddress:), @selector(threadSafeHostWithAddress:));
    SwizzleClassMethods(self, @selector(isHostCacheEnabled), @selector(threadSafeIsHostCacheEnabled));
    SwizzleClassMethods(self, @selector(setHostCacheEnabled:), @selector(threadSafeSetHostCacheEnabled:));
    SwizzleClassMethods(self, @selector(flushHostCache), @selector(threadSafeFlushHostCache));
    SwizzleClassMethods(self, @selector(_fixNSHostLeak), @selector(threadSafe_fixNSHostLeak));
}

// category continues...

What this does is swaps in our new implementations, (e.g. threadSafeCurrentHost) in place of Apple's original implementation (e.g. currentHost). Once this is done, any call to currentHost will result in our new code getting executed. Similarly, the original code that we replaced is now reachable by calling threadSafeCurrentHost.

The implementation of each of these thread-safe methods takes the form:

+ (id)threadSafeCurrentHost
{
    @synchronized(self)
    {
        return [self threadSafeCurrentHost];
    }
}

This may look like the method is just calling itself but remember, after swizzling, the call to threadSafeCurrentHost will actually invoke the original currentHost code. So this method is actually running the original code but inside a @synchronized section to maintain thread safety.

Asynchronous lookup

The best way to perform an asynchronous lookup, now that NSHost will work in a thread-safe manner, is simply to perform the lookup in an NSOperation and have that operation call back when done.

To do this, the ThreadSafety category also adds the methods:

  • currentHostInBackgroundForReceiver:selector:
  • hostWithName:inBackgroundForReceiver:selector:
  • hostWithAddress:inBackgroundForReceiver:selector:

to perform lookups and call back when done. These methods take the following form:

+ (void)hostWithName:(NSString *)name
    inBackgroundForReceiver:(id)receiver
    selector:(SEL)receiverSelector
{
    [[self hostLookupQueue]
        addOperation:
            [[HostLookupOperation alloc]
                initWithReceiver:receiver
                receiverSelector:receiverSelector
                receivingThread:[NSThread currentThread]
                lookupSelector:@selector(hostWithName:)
                lookupParameter:name]];
}

and the implementation of the HostLookupOperation's main method is extremely simple:

- (void)main
{
    [receiver
        performSelector:receiverSelector
        onThread:receivingThread
        withObject:[NSHost performSelector:lookupSelector withObject:parameter]
        waitUntilDone:NO];
}

Conclusion

You can download the complete code for NSHost+ThreadedAdditions (3kB).

The main advantage of this approach shown here is that you only need to add the files to your project — you do not need to add or change any other code to make this work.

These additions provide reasonably good thread safety for NSHost as they channel all use of the class through the thread-safe wrapping methods. The limitation to this is that Apple could add further methods in the future that circumvent the @synchonized sections we've added and the thread safety would be breached until swizzled methods were added for these new methods.

On the immutability of NSHost instances — technically, the private instance variables names and addresses of NSHost are allocated mutable but experimentally, I have verified that they are never mutated (in fact, there are no methods on NSHost that would do this). However, localizedName, available in Mac OS X 10.6, uses data from outside NSHost so might not be thread-safe.

In reality, you can avoid all of this code and simply use the CFHost API to achieve the same benefits. This ThreadedAdditions category for NSHost is an effort to continue using the simpler API of NSHost and at the same time, to demonstrate that just because Apple's implementation of something is not thread-safe in its internal implementation, doesn't mean you can't make it thread-safe in the greater context of your whole program.

Read more...

Creating iPhone and Mac icons using Inkscape (Part 2 of 2)

In this part, I expand on the simple techniques presented in the first part by adding different line, effect and texture styles. I'll also present some Mac application icons and simple texturing.

Introduction

This series covers the creation of the following different icon styles:

all-icons.png

The first icon was created in the first part of the series. I'll go through the creation of the remaining variations on the checkbox/checkmark theme in this post.

I'll assume that you've read the first part or are familiar with the techniques involved.

Icon 2: A brighter, more colorful iPhone icon

icon2.png
Goals in this section
  • Use a radial gradient
  • Learn to adjust all of the common stroke properties
  • Learn to adjust a multi-effect filter

The icon developed in Part 1 is very simple — really just a couple white lines over a typical iPhone icon background — which is appropriate for a serious application but might not stand out as prominently against other icons.

In this variation, I'll have the background reach a bright point behind the checkbox element and change the effect on the lines so that the lines look embossed into this bright point — visually integrating the background and the overlayed element.

I'll also introduce a complimentary (opposite hues) color scheme with an azure blue and a red.

A radial background

Starting with a 57x57 document as created in Part 1, add a rectangle filling the document area.

Set the fill to a radial fill and edit the gradient. In the Gradient Editor, click "Add Stop" twice to make the gradient a four part gradient. Top to bottom, the four gradient colors should be:

  1. RGBA=(192,255,250,255)
  2. RGBA=(99,164,184,255), Offset 0.26
  3. RGBA=(5,74,119,255), Offset 0.62
  4. RGBA=(0,40,80,255)

We now have a bright spot in the center of the background.

blue-dot.png

Over the top of this, paste (or recreate) the starburst effect from Part — X,Y=(-15.7,-15.7) should center it perfectly.

In the Fill and Stroke palette, set the opacity of the starburst to 100%.

Now, to make the starburst smoother, open the Filter Editor (from the Filters menu) and find the starburst's blur effect (it should be selected in the filter column when the starburst itself is selected). Select the Gaussian Blur effect and set the standard deviation to 0.75.

Different stroke properties for the checkbox and checkmark

Create the checkbox and checkmark in the same way that they were created in the first part or copy them in. If you copy them in, select both the checkbox and the checkmark and choose Filters→Remove Filters to remove the shadow and bevel effect applied in the first part.

Remove the corner radius from the checkbox (select it using the rectangle tool and set the Rx and Ry to zero). In the Fill and Stroke Editor, select the Stroke Style Tab and set the Line Width to 4.0 "px" and the Join Style to rounded. The result of these steps is to create a slightly thicker line that is curved on the corners within its width.

Select the checkmark and set the stroke color to RGBA=(255,42,42,255) and the stroke width to 4.0 "px".

altered-strokes.png
A customized "Cutout glow"

With both checkbox and checkmark selected, choose Filters→Shadows and Glows→Cutout Glow. Go to the Filter Editor and find this Cutout Glow filter. This filter will have 5 effect rows. Select the Offset row and set the X,Y offset to (0.8,0.8). Select the Gaussian Blur row and set the Standard Deviation to 1.0.

cutout-glow.png

Now follow the instructions from the "Apply the gloss effect and round corners" subsection of the previous post to complete the icon.

Icon 3: A cartoonish style

icon3.png
Goals in this section
  • Directly edit paths for greater control
  • See a Path Effect (Spiro Spline) in action

This variation will forego the starburst effect and instead go for a smoother, more "cartoonish" approach. The checkbox and checkmark will then need to be more distinctive as they will be the only significant graphical elements

Creating a path

Start with the background rectangle from the "brighter, more colorful iPhone icon" created above (if you created a cloned version for the round corners, don't copy the cloned version as it will behave strangely).

Select the Bezier Path tool (11th icon down in the Tool Area). We'll draw the rough loop first.

You can use the Bezier Path tool in one of two ways: simple click-and-release to create corner points and straight line segments or click and drag to create curve points (the dragging then affects the curvature of each point).

For simplicity here, I'll show you how to create the path using corner points and we'll apply the curve as a second step. When you're more comfortable with the Bezier Tool, this can be done as a single step.

Create a point at the 12 o'clock position, then 9, 6, 3 and then underneath the original 12. Then another inside the second twelve and then inside the 3, 6, 9, and between the first and second 12's. Then close the path by clicking on the first point.

stroke-creation.png
Bezier path creation: If you make a mistake with the path, you can either fix it later or press escape to cancel the whole path. Pressing the return-key will end the path without closing it.
Adjusting path control point properties

Using the Node Tool (2nd icon down in the Tool Area) ensure the path you just created is selected. Drag a selection box around the nodes at 3, 6 and 9 o'clock (don't select the nodes at 12 o'clock). In the toolbar at the top, select the "Make selected nodes smooth" button (should be 8th from the left in the toolbar immediately above the window).

smooth-points.png
Applying a path effect

Leaving the path selected, choose the Path→Path Effect Editor menu item. In the Path Effect Editor palette, select "Spiro Spline" from the popup menu and click the "Add" button. The "Spiro Spline" is an effect that makes smooth curved paths much easier than regular Bezier curves.

spiro-spline.png

Once this is done, you can tweak the nodes in the path (using the Node Tool) until it is the exact shape desired.

In the Fill and Stroke Editer, remove any stroke, apply a faded yellow to faded orange linear gradient fill from left to right across the checkbox loop and it is done.

checkbox-loop.png
Stroke to path

Create the checkmark as for the previous icons but set the Stroke Width to 6 "px" and the Style Join and Cap to square corners. With the path selected, choose the menu item Path→Stroke to Path. This will turn the line into a filled path. Set the stroke of this path to "no stroke" and set the fill to an orange to red linear gradient fill from left to right across the checkmark.

Now we need to adjust the checkmark to have a looser aesthetic. Select the Node Tool and the checkmark. Drag the lines in the short stem upwards slightly and the lines in the long stem inwards slightly. Adjust the control points at the ends of each stem so that they are flared outwards a little.

checkmark-adjustment.png

Follow the instructions from "Bevel effect and shadow" from Part 1 to apply these effects. Follow the instructions from the "Apply the gloss effect and round corners" subsection of the previous post to complete the icon.

Icon 4: A document-based Mac icon

icon4.png
Goals in this section
  • See the common components of a Mac document-based application icon
  • Use multiple overlapping gradients to achieve softer gradients
  • Add a texture to a background by filling with text

In terms of colors and effects, Mac icons tend to be far more subdued than iPhone icons. Where iPhone icons are only shown on the Home screen but are small and need to stand out, Mac icons may sit in the Dock for extended periods and shouldn't be distracting during this time.

For this reason, Mac icon colors tend to be slightly more subdued than iPhone icon colors and are frequently much lighter overall.

While Mac icons are typically larger (an average of around 64x64) they can also be shown at smaller resolutions. The approach to satisfying the size range is normally to compose the icon from two key parts:

  • An object or item that is easily recognizable in silhouette or at small sizes
  • Texture or subtler elements that fade away at smaller sizes but add structure and context at larger sizes

Mac icons must also handle a range of different background colors as they may be shown against people's desktop backgrounds, white folder backgrounds or against the near black of a vertical Dock. To achieve good contrast against the background, most icons are generally light in color but with a subtle shadow behind them — not for 3D effect but to contrast with lighter backgrounds. Many icons also incorporate a frame or boundary into the representation which further adds to the strength of the icon's silhouette.

A rotated background

To start the icon, create a 64x64 px document. This size will help us optimize for the expected screen resolution.

Into this, draw a 44 by 50 rectangle. Give it an azure to deep blue linear gradient from left to right and a white 3px stroke.

Using the Selection Tool (first in the Tool Area), select the rectangle. Initially, this will show the resizing arrows around the shape. Click a second time to switch these arrows to the rotating arrows (don't double click as that will switch to the Node Tool). Click and drag one of the corner arrows to rotate the rectangle by 8° (the rotated angle should be visible in the status bar at the bottom of the window while dragging but the exact angle isn't important).

rotated-gradient.png
Some effects and another gradient

On its own, a single gradient isn't a very impressive effect. The trick in making a background effect that is both attractive and subtle, is normally to layer a few different effects on top of each other.

With the rectangle selected, select "Path"→"Union". This may seem like a weird thing to do but it actually recreates the object using a path at the rotated orientation. We do this because Effects in Inkscape (like the shadow we're just about to apply) look bad (pixelated) when rotated. Recreating the object at this rotation means the effect will not have a rotation applied.

Copy and paste this rotated rectangle and put the copy next to the original. Apply a drop shadow to the original with 50% opacity, Offset of (1,1) and radius of 1.5.

Now remove the stroke from the copy. You'll notice that without the white stroke covering 1.5 px of the copy, the gradient region of the copy actually looks slightly bigger than the original. We need this shape to be the same size as the colored area of the original, so use the Selection Tool and with the rezize arrows, adjust the two to match (set the color to a flat fill like red and overlap the two objects to make it easier).

Now set the second object to have a top to bottom (parallel to its rotated axis) linear gradient fill with four color points:

  1. RGBA=(168,247,249,255)
  2. RGBA=(144,198,215,0), Offset 0.30
  3. RGBA=(95,144,175,0), Offset 0.70
  4. RGBA=(18,49,106,255)

Since this second gradient is transparent in the middle, it will show the first gradient in varying amounts through the middle. Overlapping the two should result in a softer gradient that vaguely resembles diffuse lighting across a slightly convex surface.

second-gradient.png
A light text-based texture

The formatting of the following paragraph is not an mistake.

    As indicated before, it
    helps to add a texture to
    your Mac icons. It is best
    if you have a texture or
    image that is related to
    your application — for
    this icon I don't really
    have an application, so
    I'm going to use a block
    of arbitrary text (this
    paragraph, in fact).

The Text Tool is two icons above the Gradient Tool. Click on the document to create a text object and type the text shown and formatted as above. With the text object selected, choose the Zapfino font from the font popup menu in the top toolbar. I like Zapfino because when zoomed out, it seems ornate and indistinct.

Now use the Selection Tool to scale and position the text object over the other gradient rectangles.

text.png

To add a gloss effect over everything, create a 53 by 28 rectangle, with a flat RGBA=(255,255,255,60) fill and no stroke and rotate and position it over the top half of the existing shapes.

The "representative" element

For the representative element, I'll use a checkmark in an orange circle. Create a checkmark line (same as in previous icons) set a white 5 px stroke on the checkmark.

Create a 43 by 43 circle (unlike the Rectangle Tool, you can't specify the size of a circle with the Circle Tool selected. If you want to do this, you'll need to use the Selection Tool). Set a red-orange to yellow-orange radial gradient on the object and no stroke.

Using the Gradient Tool, drag the center control point of the gradient to the bottom-right corner of the circle's bounding box, the endpoint of the horizontal stem to the bottom-left corner and the vertical endpoint to the top-right corner.

representative-element.png

With the circle selected, use the menu item Filters→ABCs→Diffuse Light. Then use the Filter Editor to set the Gaussian Blur effect of this filter to a Standard Deviation of 1.0. Then apply a drop shadow to the circle.

Finally, position everything together and the icon is complete.

Icon 5: A circular Mac icon

icon5.png
Goals in this section
  • See the common components of a Mac "appliance" application icon
  • Apply effects to a path to make the boundary shape more interesting and more distinct from the background
  • Create a texture using an effect

A circular icon is constructed in the same way as a rectangular backed icon. The only significant differences are:

  • gradients tend to be various kinds of radial gradient to give a convex feel to the round shape
  • the overlayed element will be more centered so it helps if it is less solid (thinner and lighter)
Compose a round icon

Since you've seen how to put together basic shapes and radial fills before, I'll just show you the components I used to create this icon as a graphic:

round-icon-components.png

Notice how bright the elements all are: Mac icons are normally quite bright — you want to avoid a "muddy" effect with too many dark colors.

When composing elements, if one of them is at the wrong depth (overlaps other objects wrong) you can change the depth by selecting the object and using the Page Up/Page Down keys (or by using the "Object"→"Raise"/"Lower" menu items).

Make the checkmark look interesting

The checkmark must stand alone in this icon, which means that it should have a few special effects applied to it so that it doesn't look sterile and boring. I applied the following effects to the checkmark:

  1. Filters→Non-realistic 3D shaders→Comics
  2. Filters→Shadows and Glows→Inner Glow. For this filter, I changed the Flood color to a medium blue and reduced the Gaussian Blur (now the second blur in the Effects list for this object after the Comics blur from the previous effect) to a Standard Deviation of 1.0.
  3. A drop shadow.
checkmark-with-effects.png

To texture the circle, I used the RGBA=(176,112,42,140) circle (middle element shown above) and applied a Filters→Image effects, transparent→Marbled ink effect. This gives a slightly moon cratered look that matches the somewhat planetoid shape of the object.

textured-circle.png

Conclusion

You can download an Inkscape SVG file containing all the icons and their compositions (482kB).

This two part series has been outside the normal domain of programming information that I provide. However, applications programmers will regularly find themselves needing to create, edit or adjust artwork-related assets in their applications. I hope I've given some useful tips on the way artwork assets are composed and ways you can make your artwork look good, even if it is very simple.

all-icons.png

With iPhone or Mac icons, they are typically composed from the same elements:

  1. A background gradient (or two).
  2. A texture or additional effect.
  3. A gloss or lighting highlight.
  4. A foreground element or symbol representing your application which, after the other elements are applied, need only be very simple.

With gradients and effects, it is helpful to use a few so that your icon seems rich on close inspection but to keep each one very subtle since they shouldn't distract or make the icon harder to perceive (in a quick glance, the user shouldn't even see the effects you've added).

Icons do not need to be complex; the most professional icons are often very basic. Lack of artistic skill need not be a hinderance if you keep it simple.

Read more...

Creating iPhone and Mac icons using Inkscape (Part 1 of 2)

In this two part series, I'll give a beginner's guide to creating iPhone and Mac application icons using Inkscape — a free, vector illustration program. In this first part, I'll talk about the common styles and traits of icons on the Mac and iPhone and give a step-by-step guide to creating the first iPhone icon in Inkscape.

Introduction

This series will cover the creation of the following different icons:

all-icons.png

Only the first icon will be created in this part. The remaining four will be covered in the second part.

It may seem strange to be covering icon creation in a Cocoa programming blog but the icon is an important part of an application and Cocoa is primarily an application programming environment. While larger development teams have dedicated graphic artists to create icons and other artwork assets, the reality is that on smaller teams or on solo projects, a programmer may need to create icons themselves.

The goal of this series is to show non-graphics professionals how to create graphics of an acceptable level for their applications that follow the established visual trends for iPhone and Mac apps.

A vector approach

This post is partly a response to Elite By Design's "Design The iTunes Icon For The iPhone And iPod Touch" which produced an iTunes-style icon at 125x125 pixels in Photoshop.

I wanted to show an alternative approach to the one suggested in that article. This alternative approach has the following advantages:

  • Entirely vector artwork, so it will scale from 57x57 pixels up to 512x512 pixels as required for App Store submissions.
  • Rounded corners and gloss are applied to a separate clone of the base artwork so the submission to Apple can be non-prerendered if you choose.
  • Created using free software as non-professional artists don't always have access to Photoshop.

In addition to detailing iPhone icon creation, the second part will also cover basic Mac icon design.

Established styles

I continue to be surprised when I look at screenshots of the Windows 7 taskbar.

window7taskbar.png

These are the first four icons that a Windows 7 user sees and they are the strangest collection of graphics I've ever seen. They share no obvious visual style; they are all drawn with different perspective, they all have different weights, some are glossy while others are matte, some have line edges while others are self-edged (no lines) and they don't share a color palette.

Icon styles on the Mac

By contrast, icons on the Mac tend to have more in common:

dock-icons.png

Ignoring the "Finder" icon (which is actually the "Mac OS" icon and predates Mac OS X by about 5 years), these icons come in three distinct styles:

  • Document applications (rectangular background angled 5-10° left).
  • Appliance applications (round — or at least non-rectangular — background).
  • Utilities (orthogonal rectangular background).

Originally, Apple had the guideline that utilities should look like they were "items sitting on a shelf" but only the disk utitilies still follow that guideline.

In addition to these three categories, the icons tend to:

  • Have approximately the same weight (fill roughly the same amount of their visual area).
  • Use soft gradients, sometimes (but not always) with a light gloss or highlight.
  • Use a generally bright but slightly desaturated palette of grays, azure blues, desaturated reds and sandy yellows (utility apps tend to use more blacks and darker colors).
  • Indicate their function or concept with an overlayed or nested element.
  • Are self-edged and have almost no internal lines (the outline of the icon is sometimes edged for contrast)

Of course, none of these are immutable but following them will make it easier to create a simple icon that looks like it belongs on the Mac.

Icon styles on the iPhone

The iPhone has a style that is distinct from the Mac:

iphone-home-screen.png

Aside from the obvious round cornered background and top-down gloss effect, iPhone icons tend to use:

  • Strongly saturated colors
  • A bright gradient or colorburst in the background
  • White silhouetted representative elements over the background

There is certainly variation and some icons that follow their own rules entirely (the "Notes" and "App Store" icons have little in common other than the rounded corners) but the easiest path to creating an icon that looks like it belongs on the iPhone is to incorporate these elements.

Inkscape

The tool that I will use to create the icons is Inkscape. Inkscape is a GPL-licensed SVG-based vector illustration program that you can download from inkscape.org. It is available in a Universal binary for Mac OS X 10.3.9 and newer.

inkscape.png

A nice multi-purpose icon but clearly not designed with "standard Mac app" as its primary goal.

You will need X11 installed and pre-Snow Leopard users will need an updated version of X11 (download new versions from here: http://xquartz.macosforge.org/).

Yes, Inkscape is an X11 program, which means that Open/Save dialogs are non-standard, windows may not come to the front when you expect them too and keyboard shortcuts are all Control-X instead of Command-X. Despite this, Inkscape is generally a good program — certainly far better than most X11 applications on the Mac.

If you prefer a different illustration program, most of the techniques in this guide will apply. The Filter Effects and the Path Effects are probably the points that will be most different but I'm sure you can find alternatives.

Page area

Let's start with a blank document in Inkscape.

A new document will appear when you start Inkscape or you can create a new document from the "File"→"New"→"Default" menu.

Go to the "File"→"Document Properties". Set the Default Units to "px" and the custom document size to 57 by 57.

The reason why we set the units and use the actual pixel sizes in a vector program is this will let us align points to whole value boundaries and avoid unnecessary anti-aliasing. For example, drawing a shape with its edge at Y=0.5 will cause the actual shape border to anti-alias across two different pixels when we render at 57x57 pixels but if we set the shape border's Y coordinates to 1.0, it won't have this problem.

The page area will now look tiny in the window. You can zoom in using the middle mouse button (click and drag with the middle mouse button to pan) or the "+" key. Alternately, you can zoom the document area to fill the window by pressing the "5" key.

Zooming: you will need to be comfortable with zooming in the program. The "+" and "-" keys will zoom in and out at any time. The 3 key will zoom to the selection and 4 will show all drawn elements. Clicking and dragging the middle mouse button will pan the document, clicking the middle mouse button will zoom and shift-middle mouse will zoom out.

Creating the glossy round rectangle

The Tool Area is the column of buttons down the left side of the window. The 5th tool from the top is the rectangle tool.

Red round rectangle

Using the rectangle tool, drag out a rectangle to fill the document area.

Open the Fill and Stroke palette (menu item "Object"→"Fill and Stroke" or Control-Shift-F). With the rectangle we created selected in the window, select the Stroke tab of the Fill and Stroke Palette. Make certain there is no stroke (the "X" icon should be selected). Select the Fill tab of the palette. Set a solid color fill (the solid square icon) and use the sliders to set a bright red fill (this is just so that we can see the shape easily).

fill-and-stroke-palette.png
Quick colors: you can also set solid fill and stroke colors on the selected object by left clicking (fill) or shift-left-clicking (stroke) a swatch at the bottom of the window.

We now need to edit the rectangle properties. Using the rectangle tool again, click the rectangle to select it (if it isn't already selected). In rectangle edit mode, a toolbar will appear at the top of the window labelled "Change" with coordinates "W", "H", "Rx" and "Ry". Set the "W" and "H" to 57 — this will make the rectangle exactly 57 pixels wide and high (if the rectangle auto-locked to the edges of the document, these values may already be set). Set the "Rx" and "Ry" to 10 — this will set the corner radii to 10 (a round rect).

round-rect.png
Numerical accuracy: I'm going to quote a lot of coordinates and color values in this post but this is only so I can communicate what I'm doing. Most of the time, you do not need to be pixel accurate and can do things more approximately if you prefer.

Using the selection tool (the first tool in the Tool Area) select the rectangle. The object's "X" and "Y" coordinates will appear in the toolbar at the top. Set these to zero. The rectangle is now exactly the size of the document with round corners.

The gloss round rectangle

Copy the red round rectangle object (select it and press Control-C) and paste it (Control-V) somewhere else (when pasted, the object will be centered where the mouse is, so place the mouse over a different part of the document).

Copy and Paste bug: if the Copy and Paste fails (you get a bitmap instead of a proper editable object or nothing seems to happen), then you may be seeing a bug in Inkscape due to recent X11 changes. To work around this bug, go to the X11 preferences and on the Pasteboard tab, disable "Update Pasteboard when CLIPBOARD changes". Alternatively, you can use "Edit"→"Duplicate" to duplicate without copying.

With the copy selected, go to the Fill tab of the Fill and Stroke palette. Set a radial fill for the object (4th icon from the left at the top). If you've set the red color, then the radial gradient will initially look like a red dot fading outwards.

Click the "Edit" button in the Fill tab to edit the gradient. In the "Gradient Editor" that appears, the popup menu at the top will contain two items (the opaque red color and the fully transparent red color). Hit the "Add Stop" button twice to add two extra items in the gradient.

Edit the topmost item in the list of colors (the opaque red color) and set it to white with an alpha value of 86. Set the second item to white with an alpha of 75. Set the third to black with an alpha of 60. Set the final item to white aith an alpha of 0.

You also need to set the offset of the two middle colors. The black color should have an offset of 0.63. The white color should have an offset of 0.62.

This round rectangle should now look like a faint gray donut. Select it and set its "X" and "Y" coordinates to (0,0) (so that it perfectly overlaps the original red round rectangle).

With the faint gray donut selected, choose the Gradient Tool (second last in the Tool Area — if your vertical screen resolution isn't very high, you may need to select the Gradient Tool from the popup menu at the bottom of the Tool Area). An "L" shape of control points should appear over the donut.

Drag the control point that appears in the middle of the donut to the middle of the top edge of the round rect (it should lock onto the point with the text "Handle to bounding box").

Drag the round control point at the end of the horizontal arm of the "L" to X=-50. You can see the "X" value of the cursor at the bottom right of the window. Hold down the "Control" key while doing this to ensure that the "Y" value remains the same. Similarly, drag the round control point at the end of the vertical arm to Y=12.

gradient-control-points.png

On the Stroke tab of the Fill and Stroke palette, set a linear gradient stroke (third icon from the left at the top) for the gloss object. On the Stroke Style tab, set the line width to 1.0 px.

On the Stroke tab, edit the gradient. Set the start color to white and the end color to RGBA=(255,255,255,0). Using the Gradient Tool, select the gloss object. There should now be an extra set of control points in a horizontal line across the middle of the object corresponding to the stroke's gradient. Drag the start point of this line (square control point) to the top right corner of the object and the end point of the line (circular control point) to a position three quarters the way up the right-hand side of the object.

stroke-gradient.png

Since the stroke added to the gloss object changed the size of the object, you will need to re-set the size of the gloss object to 57x57 at X,Y=(0,0).

You should now have a glossy red round rectangle in the style of an iPhone icon. If you know what you're doing in Inkscape, you can move these objects to another layer and hide them now however, it's probably easiest just to save this document and copy these objects when they are needed later.

The first iPhone icon

Blue-green background

Create a 57 by 57 rectangle at X,Y=(0,0) again, using the same approach as the red rectangle from the previous section but leave the corners square (you may need to explicitly set Rx and Ry to zero since it may remember the radius from before).

Set the fill of this rectangle to a linear gradient (third icon from the left at the top of the Fill tab in the Fill and Stroke palette). Edit the gradient and set the start point to RGBA=(15,112,126,255) and the end point to RGBA=(0,0,53,255).

Using the Gradient Tool from the Tool Area, select the rectangle and drag the gradient starting point (the square control point) to the center of the bottom edge of the rectangle. Drag the gradient end point (the round control point) to the center of the top edge of the rectangle.

blue-green-gradient.png
Gradient colors: almost every gradient you use should involve a hue shift. When you want an actual 3D or lighting effect, you can also apply a luminance shift. The gradient here shifts from blue into the green direction as it lightens (a common choice). The other most common gradient would probably be from a darker red or orange towards a lighter yellowy orange. Hues on the green side of yellow or purple hues are rarely ever used.
Starburst object

Now, using the Stars and Polygons tool from the Tool Area (8th from the top) and drag out a shape (it will probably appear as a 5 point star — if it isn't a star, click the star icon in the top toolbar). With the Stars and Polygons tool and the object still selected, you should be able to edit the properties of the star. Set the number of corners to 350, the spoke ratio to 0.3 and the Randomized property to 0.015. Choose the Select and Transform tool (first tool in the Tool Area) and select the star. You can now set the width and height both to 87 and the X,Y to (-15,-15).

In the Fill and Stoke palette, set the opacity of the star to 50%.

Then, set a radial fill on the star from a start color of RGBA=(255,255,255,0) to an end color of RGBA=(0,235,255,255). This radial gradient fades out in the middle which will help the checkbox stand out from the background more.

A blur effect on the starburst

With the star object still selected, select the menu item "Filters"→"ABCs"→"Simple Blur". Then select the "Filters"→"Filter Editor..." menu item. This will display the Filter Editor palette.

Space limitations: If the Fill and Stroke Palette is still showing when the Filter Editor appears, you'll notice that they don't fit well together down the right margin. I recommend you either close the Fill and Stroke Editor or drag the Filter Editor off into its own window.

There should be one filter listed in the list of filters — this is the filter you just created. When you select the filter in the list, the Effect "Gaussian Blur" will appear in the Effect column at the right. Select the Gaussian Blur and the "Effect Parameters" tab will appear at the bottom. Set the "Standard Deviation" to 0.25.

starburst.png

You can also apply "Blur" using the Fill and Stroke palette. The blur radius at the bottom of this palette is 2.74 times the Standard Deviation applied here (no, I'm not really sure why the difference is 2.74 times).

The checkbox and checkmark objects

Now create a 29x29 round rectangle with corner radius 4 at X,Y=(14,14). This is the checkbox. This time, set no fill (the "X" icon on the Fill tab of the Fill and Stroke palette) and set a plain stroke (second icon from the left at the top of the Stroke tab) with a white color. On the "Stroke Style" tab, set the width to 3.0 "px". While here, set the "Cap" to round. It won't matter as much for this object, but we're just about to draw a line and we want it to have round endcaps.

Select the Bezier Line tool (11th icon down in the Tool Area). Click the mouse and release to create points at X,Y = (19.5,30), (28.5,20) and (47,48). Press the return key when done to finish the path. This is the checkmark. Now select the Node Tool (second icon from the top of the Tool Area) and select the checkmark. Click and hold the mouse in the middle of each line segment and drag up slightly to give the lines a slight curve. You can use the control points to tweak the effect if you're not happy.

node-tool.png
Bevel effect and shadow

Select the checkmark and the checkbox. From the Filters menu select "Bevels"→"Ridged Border". Then from the Filters menu select "Shadows and Glows"→"Drop Shadow", set the blur to 2.0, the opacity to 35%, the offset to (3,3), hit the "Apply" button and close the Drop shadow dialog.

Speed tip: when zoomed in on objects using effects, the rendering can get slow. To disable effects or to drop entirely into wireframe mode, choose "No Filters" or "Outline" from the "View"→"Display Mode" menu or press Control-Keypad5. The "Ridged border" effect is especially slow in the current version of Inkscape — I recommend zooming out before you apply it and turning effects off before you zoom in close.

If you want to fully integrate the checkmark and the checkbox, you can convert the checkbox object to a path, the checkmark stroke to a path and then create a union of the two. I'll leave that to you if you're interested.

Apply the gloss effect and round corners

Select the green gradient background, the starburst, the checkbox and the checkmark and group them all together (Control-G or menu "Object"→"Group"). This will let you select them all in one go (ungroup with Control-Shift-G or double-click the group to select objects within the group without ungrouping).

With the group selected, from the Edit menu select "Clone"→"Create Clone". This will create a copy that continues to update when the original updates. Move the clone to X,Y=(-115.7,-15.7) (this coordinate include extra padding of approximately 2.74 times the starburst's blur standard deviation of 0.25 which is the amount that a blur will expand an object's boundary).

Now we need the red glossy round rectangle. If you saved them in a different document, copy them into this document now. Select the red background and gloss (drag a rectangle around both using the Selection Tool) and set the X,Y coordinates of the two of them to (-100,0). This may make the two objects hidden behind the cloned group objects so press the "Home" key (or select Raise to Top from the Object menu).

redrectclone.png

Drag the gloss and the red rectangle off of the objects they are covering (it doesn't matter where you put them). Select the cloned group and the red round rectangle but not the gloss gradient. Undo the two object moves. This should leave the cloned objects and the red round rectangle selected but all of the objects on top of each other. From the Object menu, select "Clip"→"Set". This should clip the cloned group to the boundary of the red round rectangle, and make the red round rectangle disappear.

Clipping: when clipping in Inkscape, the topmost object is always used as the clipping boundary and all other selected objects are clipped to its boundary.
side-by-side.png

Export the bitmap

Congratulations, your iPhone icon is complete.

You can export the prerendered (cloned, glossed and rounded) version to a PNG by selecting the gloss gradient that's over the clipped shape and selecting "Export Bitmap" from the "File" menu. Make sure that "Selection" is highlighted in the window that appears and set the width and height of the exported image to whatever size you want. Use the Browse button to select a location then hit the export button.

If you want to send the non-prerendered version to Apple, then select the uncloned group and export from that. 57x57 for the application icon and 512x512 for the high resolution version in your App Store submission.

Resampling: You may get a better effect on the small icon if you export at a larger size and use another program (Preview, GIMP, etc) to scale it down. This may give better anti-aliasing performance — particularly if your resizing program uses Lanczos resampling.

If you'd like your icon as a PDF, SVG or a number of other vector graphics types, you can choose "Save As..." and save to the format of your choice.

Conclusion

You can download an Inkscape SVG file containing the final icon (122kb). Note: Safari and other programs will open SVG files but the effects (shadows, blurs, etc) will only appear if the SVG is opened in Inkscape.

In the second part, I will go through the steps for other icons, showing different stylistic options and explaining more of the effects and graphical elements you can use to create your icons. I'll look closer at filter effects in Inkscape, creating more sophisticated line paths, using gradients in multiple directions to achieve softer effects and creating simple textures to fill blank areas.

Read more...

Memory and thread-safe custom property methods

Objective-2.0 property methods are a nice convenience but if you need to override a property implementation — particularly an atomic, retained or copied object setter property — there are some potential bugs you can create if you don't follow the rules carefully. I'll show you the pitfalls and the correct way to implement a property accessor. I'll also show a way to directly invoke hidden runtime functions to let Objective-C perform atomic getting and setting safely for you.

Custom getter and setter methods for implicitly atomic types

For implicitly atomic types or for types where memory management doesn't apply, custom getter and setter methods in Objective-C are easy. These "easy" situations include:

  • Basic value types (char, short, int, float, long, double, etc).
  • Objective-C objects in a garbage collected environment
  • Assigned (non-retained) pointers

For these types, it is pretty hard to get a custom getter or setter method wrong. For the following property declaration:

@property SomeAtomicType somePropertyVariable;

the custom getter and setter simply look like this:

- (SomeAtomicType)somePropertyVariable
{
    return somePropertyVariable;
}
- (void)setSomePropertyVariable:(SomeAtomicType)aValue
{
    somePropertyVariable = aValue;
}

Common mistakes in accessor methods for non-atomic types

Non-atomic types require greater care. These types include:

  • Objective-C objects in a manually managed memory environment
  • structs and other compound types

Given how simple custom getter and setter methods are for atomic types, it is easy to be complacent about implementing methods for these types. However, following the wrong approach can lead to memory crash bugs and lack of proper thread safety.

To illustrate how simple it can be to introduce bugs while implementing a custom setter method, consider the following declared property:

@property NSString (copy) someString;

A hasty implementation of the setter might be:

- (void)setSomeString:(NSString *)aString
{
    [someString release];
    someString = [aString copy];
}

This implementation actually contains two bugs:

  1. This method is not atomic.
    The someString object changes twice: once on release and again when it is assigned the copied object's address. This method is not atomic and therefore violates the declaration (which omits the nonatomic keyword and therefore requires atomicity).
  2. The assignment contains a potential memory deallocation bug.
    If someString is ever assigned its own value, it will release it before copying it, causing potential use of a released variable. The code: self.someString = someString; is an example of this potential issue.

Don't feel too bad if you've ever made these mistakes. I spent some time looking at clang's synthesized method implementations when I was researching this post and I noticed that they've forgotten to handle struct accessor methods in an atomic manner when required.

Safe implementations of custom accessor methods for non-atomic types

To address this second issue, Apple's Declared Properties documentation suggests that your setter methods should look like this:

- (void)setSomeString:(NSString *)aString
{
    if (someString != aString)
    {
        [someString release];
        someString = [aString copy];
    }
}

This only fixes the memory issue, it doesn't fix the atomicity issue. To handle that, the only simple solution is to used a @synchronized section:

- (void)setSomeString:(NSString *)aString
{
    @synchronized(self)
    {
        if (someString != aString)
        {
            [someString release];
            someString = [aString copy];
        }
    }
}

This approach will also work for retain properties as well (simply replace the copy method with a retain.

To maintain atomicity, you also need a retain/autorelease pattern and lock on any getter methods too:

- (NSString *)someString
{
    @synchronized(self)
    {
        id result = [someString retain];
    }
    return [result autorelease];
}

The @synchronized section is only required around the retain since that will prevent a setter releasing the value before we can return it (the autorelease is then safely done outside the section).

For struct and other compound data types, we don't need to retain or copy, so only the @synchronized section is required:

- (NSRect)someRect
{
    @synchronized(self)
    {
        return someRect;
    }
}
- (void)setSomeRect:(NSRect)aRect
{
    @synchronized(self)
    {
        someRect = aRect;
    }
}

A faster, shorter way to implement custom accessors

There are two negative points to the custom accessor methods listed above:

  • They need to be coded exactly to avoid bugs.
  • The @synchronized section on self is coarse-grained and slow.

There is another way to implement these methods that doesn't require as much careful coding and uses much more efficient locking: use the same functions that the synthesized methods use.

The following functions are implemented in the Objective-C runtime:

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic);
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic,
    BOOL shouldCopy);
void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic,
    BOOL hasStrong);

While these functions are implemented in the runtime, they are not declared, so if you want to use them, you must declare them yourself (the compiler will then find their definitions when you compile).

These methods are much faster than using a @synchronized section on the whole object because (as shown in their Apple opensource implementation) they use a finely grained, instance variable only spin lock for concurrent access (although the copy struct function uses two locks following an interface design mixup).

When you declare these functions, you can also declare the following convenience macros:

#define AtomicRetainedSetToFrom(dest, source) \
    objc_setProperty(self, _cmd, (ptrdiff_t)(&dest;) - (ptrdiff_t)(self), source, YES, NO)
#define AtomicCopiedSetToFrom(dest, source) \
    objc_setProperty(self, _cmd, (ptrdiff_t)(&dest;) - (ptrdiff_t)(self), source, YES, YES)
#define AtomicAutoreleasedGet(source) \
    objc_getProperty(self, _cmd, (ptrdiff_t)(&source;) - (ptrdiff_t)(self), YES)
#define AtomicStructToFrom(dest, source) \
    objc_copyStruct(&dest;, &source;, sizeof(__typeof__(source)), YES, NO)

I like to include the "To/From" words so I can remember the ordering of the source and destination parameters. You can remove them if they bother you.

With these macros, the someString "copy" getter and setter methods above would become:

- (NSString *)someString
{
    return AtomicAutoreleasedGet(someString);
}
- (void)setSomeString:(NSString *)aString
{
    AtomicCopiedSetToFrom(someString, aString);
}

and the someRect accessor methods shown above would become:

- (NSRect)someRect
{
    NSRect result;
    AtomicStructToFrom(result, someRect);
    return result;
}
- (void)setSomeRect:(NSRect)aRect
{
    AtomicStructToFrom(someRect, aRect);
}

Conclusion

Most of the accessor methods I've shown here are atomic but in reality, most Objective-C object accessors are declared nonatomic.

Even if your properties are declared nonatomic, the memory management rules still apply. These rules are important to follow since they can lead to some very obscure and hard to track down memory bugs.

The macros I've provided are all for atomic properties. For non-atomic properties the boilerplate assignment code is probably simple enough to remember. If not, you could also use a macro:

#define NonatomicRetainedSetToFrom(a, b) do{if(a!=b){[a release];a=[b retain];}}while(0)
#define NonatomicCopySetToFrom(a, b) do{if(a!=b){[a release];a=[b copy];}}while(0)

Update: following comments below, I realize I omitted to qualify the situations in which these accessors are thread-safe. Specifically:

  1. These setter methods are only thread-safe if the parameters passed to them are immutable. For mutable parameters, you may need to ensure thread safety between mutations on the parameter and the assignment of the property.
  2. Atomic accessors only provide thread safety to an instance variable if they are the sole way you access the instance variable. If non-property access is required, you must ensure shared thread safety between property accessor methods and the non-property access.
  3. Atomic assignment for the "implicitly atomic" types I listed does not mean that all CPUs/cores see the same thing (since each CPU/core could have its own cache of the value) — it only ensures that value is wholly set without possibility of interruption. If you require all CPUs/core to be synchronized and see the same value at a given moment, then even the "implicitly atomic" types may require volatile qualifiers or a @synchronized section around the assignment to flush caches.
Read more...