Search
Follow
Recent Comments

Entries in objective-c (13)

Monday
Jun202011

Thoughts on iOS 5

Now that WWDC is a fading memory (when will those videos of the sessions show up for those of us who could not go…) I wanted to comment on the two things I am most excited about with iOS 5. Of course everything is under NDA so my comments are limited to what was in the keynote or has otherwise been made public by Apple.

iCloud

A lot of details about iCloud were revealed in the keynote but I am interested in what it might mean for iOS developers.

Consider the case where I have a reading application or a game where I already save things like bookmarks or game progress to a local plist file on the device. If I have the same app installed on both my iPhone and my iPad I have no way to have the app stay in sync between those two devices. The same applies if I have an app that creates content, currently the only way to make that content turn up on all devices is to use the cumbersome mechanism provided by iTunes or an external service such as dropbox.

There are a great many iOS apps which are effectively stand-alone apps that fit this model. Since the apps do not need to connect to a central server there is no requirement for the app developer to deploy and run a hosted server which costs real money. However the downside is that each instance of the app running on a particular device is completely ignorant of other iOS devices the user may have.

For apps that already rely on a web service or some other hosted server I suspect iCloud will not make much difference but for all other apps I expect it to have significant impact. In fact I would expect all iOS apps to allow for basic settings and preference information to be sync’ed between all iOS devices the user has. This means that if I have been using an app on my iPhone and then decide to also install it on my iPad that the app starts up on the iPad with exactly the same settings and app context that it has on the iPhone and that the two devices stay in sync.

If you are looking at moving you apps to iOS 5 (and why would you not) then I think building in a basic level of iCloud support for settings and app state should be one of the first things you target.

Automatic Reference Counting (ARC)

This announcement, tucked away on a single keynote slide, during the WWDC keynote was really totally unexpected. Objective-C 2.0 has language support for garbage collection but it can only be used with Cocoa apps running on OS X. For iOS we have been stuck with performing our own memory management using retain, release and autorelease. Once you get the hang of the Objective-C conventions I do not find managing the retain/release cycle to be that hard but it remains a big hurdle for new iOS developers to jump over and a source of memory leaks and app crashing bugs.

I had long assumed that as iOS devices get more powerful we would eventually arrive at a point where Apple would also support garbage collection on iOS unifying the two Cocoa platforms. I was not expecting that to happen this year but I was guessing or hoping it would be coming soon. Apple though would not be Apple if they could not occasionally pull a rabbit out of the hat and do something unexpected.

You can find a lot of detail on ARC on the LLVM compiler site - see Automatic Reference Counting. Be warned that it is not easy reading and you may want to wait until the WWDC session videos are available. In brief, and again staying on the right side of the NDA, it is a compiler feature that promises to automatically take care of the retaining/releasing of objects for us. The promise for an iOS developer is that you will not need to worry about retaining and releasing objects manually. The LLVM compiler is now smart enough to manage the objects for you and automatically insert the retains/release methods for you at compile time.

If you have used the Clang language analyser you will have already seen how smart the LLVM parser has become. It is already capable of highlighting errors with retain and release so I guess it was the logical next step to just let the compiler insert the correct memory management methods into the code for us.

When Objective-C 2.0 came along and introduced properties with the dot syntax it created some controversy for long time Objective-C programmers who felt it hid what was happening under the covers and could be misused. I guess the same will be true with ARC with many experienced developers preferring to stay with manual memory management. It is too early to pass judgement but in theory if ARC lives up to its promise it could both simplify and speed up iOS apps without the need to implement garbage collection which as Steve would say is magical.

Tuesday
May172011

Dealing with Failure in Objective-C initializers

Most introductory texts on Objective-C cover the two step process to allocate and initialize a new object but do not say much about what you should do if the initialization fails. I suspect the reason for this is that most of the time initializers don’t do much that could go wrong. One situation where an initializer can fail is when it depends on a resource which may not always be available or which could be in error. For example, data which must be retrieved from a file or a remote network resource.

Initializing Objects

Before looking at how to handle failure conditions in the initializer it is worth reviewing some of the key points about an Objective-C initializer. A simple but fairly typical initializer for an Objectve-C class may look something like this:

  - (id)initWithValue:(NSUInteger)someValue {
 
    self = [super init];
    if (nil != self) {
 
      // Set some ivars
      someIvar = someValue;
    }
 
    return self;
  }

 

The key points to note are as follows:

  • By convention the name of the initializer always starts with “init”
  • The return type should always be “id”
  • The initializer should always call the designated initialiser of its superclass. If the class is a direct subclass of NSObject (e.g. @Interface MyClass : NSObject) the designated initializer is “init”. If you are subclassing some other class you should check the class documentation or interface file to determine the designated initializer.
  • The value returned by the designated initializer should be assigned to self
  • If and only if the call to the initializer of the superclass did not return nil you can access the instance variables and set the values you need the new object to contain
  • Setting the ivars is done directly rather than via self (e.g. self.someIvar=…) to avoid invoking any getter/setter methods.
  • When an object is allocated all of the instance variables are set to 0 (or nil in the case of object pointers) so you do not need to zero ivars in the initializer.
  • The initializer should return self if successful otherwise it should return nil.

Dealing with Failure

In this simple example of an Objective-C initializer handling failure is pretty simple. The only way the initializer can really fail is if the initializer of the superclass fails. In that case there is nothing to do but return nil to the caller (making sure not to access any of the ivars). Testing for a failure at this point is good practise even if you think the initializer can never fail since you never know how the superclass may be modified in the future.

So what happens when our initializer is a bit more complicated and needs to access some external resources to properly initialize the object:

  - (id)initWithFile:(NSString *)filePath {
 
    self = [super init];
    if (nil != self) {
      if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        // More code to read, validate and use file contents to
        // init the object
      } else {
        [self release];
        return nil;
      }
    }
 
    return self;
  }

 

In this case we have an initializer that takes a single parameter which should be the path to a file used to initialize the object. After first initializing the superclass and checking for failure as before the class checks that the file actually exists. If the file does not exist the object cannot be initialized so we need to clean up and return nil to the caller.

However in this case we have already successfully initialized the superclass so we have a partially initialized object. We do not want to return this object to the caller since it is not fully initialized but if we just return nil we will create a memory leak. The solution is to send the release message to the superclass and let it clean up the resources allocated by the superclass.

In practise this type of initializer would be more complicated with many ways for failure. For example, we may start reading the file and only then find it is invalid. However the basic approach to failure is always the same. Any resources allocated in the initializer need to be released then the release message needs to be sent to the superclass. Finally we should return nil to the caller.

Tuesday
Apr262011

Use of properties by Xcode 4 templates

I little while ago I posted about some techniques to remove duplicate code when declaring instance variables (see DRYing your instance variables). When I wrote that post I had not managed to take a look at the new templates provided in Xcode 4. It turns out that Apple has changed the code generated by the templates to use a very similar approach (which is reassuring to me at least).

For example if you create a new project based on the Utility Application template the interface for the Application Delegate class looks like this:

    @class MainViewController;
    @interface UtlityAppDelegate : NSObject <UIApplicationDelegate> {
    }
    @property (nonatomic, retain) IBOutlet UIWindow *window;
    @property (nonatomic, retain) IBOutlet MainViewController *mainViewController;
    @end

The instance variables are not explicitly declared instead they rely on a feature of Objective-C 2.0 and the modern runtime to synthesize them along with the getter/setter methods. The relevant synthesize statements from the implementation file are as follows:

    @synthesize window=_window;
    @synthesize mainViewController=_mainViewController;

Here another feature of the language is used to make the name of the instance variable different from the name of the property. So the property named “window” will in its getter/setter methods refer to an instance variable named “_window”. I covered why this is a good idea in an earlier post but in short it makes it clear when you are referring to the instance variable directly and when you are using the getter/setter methods. The dealloc method is one place where you generally want to avoid the getter/setters and access the instance variable directly. This should now be clear from the dealloc method generated by the Xcode templates:

    - (void)dealloc
    {
        [_window release];
        [_mainViewController release];
        [super dealloc];
    }

In general it also seems that the template generated code is much more consistent about accessing instance variable via self rather than directly. Apologies if I seem to be beating this topic into the ground but I think it is important and it is interesting to see the approach that Apple is now promoting in the templates.

Friday
Apr222011

Private ivars

I was skimming through the Stanford iPhone course last night (see previous post) and watched lecture 3 on Objective-C. One statement that caught my eye (see page 12 of the lecture notes) was the suggestion that you mark all of your instance variables @private. The instructor does not provide much of an explanation as to why he recommends this but it is worth spending a few minutes to ask if he is right and why?

Instance Variable Scope

Objective-C allows you to set four levels of scope for an instance variable as follows:

  • @private - accessible only within the class that declares it
  • @protected - accessible within the class that declares it and all subclasses. This is the default.
  • @package - accessible everywhere within the executable package (e.g. a framework library) but not outside
  • @public - accessible everywhere

Leaving aside the @package scope which is a bit of a special case useful when creating frameworks I hope you agree we can also eliminate @public as a possible choice. Making our instance variables public defeats the idea of data hiding or encapsulation which is a fundamental principle of object-oriented programming. Keeping the internal representation of an object “hidden” from the users of the class makes it much easier to change later as well as making the class more robust (since external users cannot mess with the internal object state).

So that leaves @private or @protected as possible choices. If you do nothing the default is protected which means any subclass of our class will be able to directly access the instance variables. This means that even if you have created getter and setter methods the subclass is not forced to use them to access the instance variables.

If on the other hand you explicitly mark an instance variable as @private a subclass no longer has direct access. For example, if I have a Person class defined as follows:

    @interface Person : NSObject {
    @private
        NSString *givenName;
        NSString *surname;
        NSString *fullname;
    }
 

If I then subclass Person to create an Employee class:

    @interface Employee : Person {
        ...
    }

I cannot write an Employee method that directly accesses one of the Person instance variables:

    @implementation Employee
    - (void)logMyName {
        NSLog(@"%@",self.fullname);  // this will work
        NSLog(@"%@",fullname);       // this will not work
    }
    @end
 

If it is not clear why self.fullname is allowed in this case you may want to refer back to a previous post on understanding self. Remember that self.fullname is the same as [self fullname] which ends up trying to execute the getter method named fullname rather than directly accessing the instance variable. This assumes of course that the Person class has defined the getter method. If the getter method does not exist then even self.fullname would be invalid.

The advantage in this case of making the instance variables private is that we enforce access by the Employee class to be via the getter method. If at a later date we want to change the implementation of the Person class, perhaps by removing the ivar and generating the value from the givenName and surname, we can be sure that no code in the Employee class will break.

There is an additional and more subtle advantage to using @private to force the subclass to use the setter method. The setter method will often contain code to correctly manage and release memory or other logic to ensure only valid values can be set. If the subclass directly accesses the ivar it bypasses this code in the setter potentially introducing problems which can be tricky to track down.

Apple Guidelines

The Apple Coding Guidelines for Cocoa also make a couple of recommendations on declaring instance variables:

  • Avoid creating public instance variables. Developers should concern themselves with an object’s interface, not with the details of how it stores its data.

  • Explicitly declare instance variables either @private or @protected. If you expect that your class will be subclassed, and that these subclasses will require direct access to the data, use the @protected directive.

This is saying pretty much the same thing - avoid @public, use @protected if you need subclasses to have direct access to the ivar otherwise use @private.

Summary

So to come back to the original question, should you make all of your instance variables @private? There is an argument for using @protected if you are writing a class that you expect to be subclassed. However I would not do this because of some perceived performance advantage from allowing a subclass direct access. The performance overhead of calling getter and setter methods is in any case unlikely to have a noticeable impact on most Cocoa or iOS apps.

Perhaps the question is unfair as it is difficult to come up with a rule that always applies. Sooner or later a special case comes along which requires you to break the rule. However starting out with @private as the default and switching to @protected only when you really need to is a pretty good rule of thumb.

Saturday
Apr092011

Objective-C Fundamentals

There seems to be a never ending number of books which provide an introduction to iPhone and iOS programming. Both the introductory books that I used when starting out with the iPhone are now long overdue an update so I have been on the lookup for something to recommend to new iOS programmers for a while.

Objective-C Fundamentals by Fairbairn, Fahrenkrug and Ruffenach (Manning Publications) takes a slightly different approach to most such books by focussing on the Objective-C language rather than Cocoa Touch. The Cocoa Touch framework is mentioned but more as a way to illustrate aspects of the language. The book is subtitled “For iOS 4 and the iPad” so the example code and framework discussions are targeted at iOS rather than Mac OS X. Having said that most of the language concepts (with the possible exception of memory management) apply equally to OS X programming.

This review is based on an early access edition so there could be some minor changes in the final released version.

Part 1 Introduction to Objective-C

The book starts with the creation of a simple app to introduce Xcode and related tools (examples use Xcode 3). Once that is out of the way it introduces the basic data types. A lot of this discussion is not really Objective-C specific since the data types discussed are really C data types. So C structures and arrays are covered for example. If you are coming to iOS programming with prior knowledge of C this will not be anything new and you can probably skim through the early chapters. However for somebody without much experience of C these earlier chapters are well done. There is a fuller discussion of C basics in the appendix for those that need it.

Things get more interesting when the concept of objects are introduced and I think the authors do a good job of covering the Objective-C way of doing things. The NSString class gets good coverage as do the NSArray and NSDictionary classes. All of which need to be well understood by an iOS programmer. Enumeration and the boxing of basic data types so that they can be stored as objects are also covered. There is some good attention to detail here as some of the more obscure parts of the language that are often overlooked get explained (for example the difference between nil, NULL and NSNull).

Part 2 Creating and Extending Classes

With the basics out of the way the book starts to dig into the core of the Objective-C language. The sections on creating classes cover declaring instance variables and methods. The key concept of getter and setter methods is introduced first before covering the use of property and synthesize declarations and the dot syntax. Subclassing is covered but so are Categories as an alternative to subclassing which is useful. Interestingly there is also a discussion of Class Clusters. I should say that advanced topics such as Class Clusters are not covered to the detail you would find in a book such as Cocoa Design Patterns but it is good to see that they at least get a mention and brief explanation.

The chapter on protocols uses the UITableView as one of several examples but as I said previously this is to illustrate the language concept more than to explain iOS table view controllers. The chapter on dynamic typing covers another of the less well understood Objective-C topics digging into messaging, selectors and runtime typing.

A key chapter in any book on Objective-C or Cocoa has to be the one on memory management. The authors explain memory management through object ownership and use that to introduce the retain/release methods (there is no discussion of garbage collection since this is an iOS book). Autorelease pools are covered as expected but so are memory zones which I confess I have never had to use with iOS. Overall this is a good explanation of a topic that most new iOS programmers struggle with. My only criticism is that you have to wait until chapter 9 for such a key topic to be covered.

Part 3 Advanced Topics

The final section of the book covers a number of advanced topics not all of which are really Objective-C language features. Having said that I think the chapter on NSError is not out of place as it covers why it is often used in Cocoa applications where other languages might instead use exception handling. The chapters on Key Value Coding (KVC), blocks and Grand Central Dispatch are all good introductions to complex topics which are becoming increasingly important for iOS developers.

The one topic that seemed slightly out of place to me was the one on Core Data. There is nothing wrong with the chapter, it is a good introduction to an important topic, I just think it would fit better in a book focussed on the Cocoa frameworks rather than Objective-C. The final chapter covers debugging with emphasis on detecting memory issues such as leaks and zombies. There is no mention of unit testing which would have been a nice addition.

Who Should Read This Book?

With so many books available all wanting to help you master iOS programming it can be difficult to recommend one over another.

I would recommend Objective-C fundamentals to people coming new to the language, perhaps without prior knowledge of C, who really want to master the finer points of the language. The only caveat is that you will probably want to start with a book that covers more of the Cocoa Touch frameworks and iOS development. This book is more suited to filling the gaps in your understanding of Objective-C rather than learning iOS. As such it is likely to be more useful to intermediate iOS developers rather than absolute beginners.

So to summarise this still may not be the first book I recommend you buy on iOS programming but it would make a good second follow up book for many people.