Cocoa

Creating singletons using dispatch_once

1

Love them or loathe them, sometimes you need to have a singleton. In fact every iOS and Mac OS application has at least one, UIApplication or NSApplication.

So what is a singleton? Wikipedia defines it as:

In software engineering, the singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object.

Or as I would put it:

A singleton is a class, where only one instance of it can instantiated.

Although this is the actual definition of a singleton, this isn’t always the case in the world of Foundation. NSFileManger and NSNotificationCenter for example, are usually accessed through their class methods defaultManager and defaultCenter respectively. Although not strictly a singleton, these class methods return a shared instance of that class that developers can then access throughout their code. It is this approach that we will be looking at in this post.

There has always been a debate on the best way to implement the singleton pattern using Objective-C, and developers (including Apple) seem to have been changing their minds every couple of years. When Apple introduced Grand Central Dispatch (GCD) (in Mac OS 10.6 and iOS 4.0) they introduced a function that is perfect for implementing the singleton pattern.

This function is dispatch_once:

   void dispatch_once(
   dispatch_once_t *predicate,
   dispatch_block_t block);

This function takes a predicate (which is a long, that in reality acts as a BOOL) that the dispatch_once function uses to check if the block has already been dispatched. It also takes the block that you wish to only be dispatched once for the lifetime of the application, for us this is the instantiation of our shared instance.

Not only does dispatch_once mean that your code will only ever get run once, it is also thread safe, which means you don’t have to bother with using anything like @synchronized to stop things getting out of sync when using multiple threads and/or queues.

This is verified by Apple’s GCD Documentation:

If called simultaneously from multiple threads, this function waits synchronously until the block has completed.

So how would you use this in practise?

Well lets say you have a Account Manager class, and you want to access a shared instance of this class throughout your application. You can simply implement a class method like the one below:

+ (AccountManager *)sharedManager
{
        static AccountManager *sharedAccountManagerInstance = nil;
        static dispatch_once_t predicate;
        dispatch_once(&predicate, ^{
                sharedAccountManagerInstance = [[self alloc] init]; 
        });
    return sharedAccountManagerInstance;
}

This means whenever you want access this shared instance all you need to do is:

AccountManager *accountManager = [AccountManager sharedManager];

And that’s all there is to it, you now have a shared instance that you can access throughout your application, which will only be created once.

This approach has many advantages:

  1. It is thread safe
  2. It will keep the static analyser happy
  3. It is compatible with Automatic Reference Counting (ARC)
  4. It only requires a small amount of code

The only disadvantage with this approach is that it will still allow a non shared instance to be created:

AccountManager *accountManager = [[AccountManager alloc] init];

Sometimes you will actually want this behaviour, but it is something you need to be aware of when you really only want one instance of a class to ever be instantiated.

URL Encoding

5

If you have tried to send any information using a GET web request, you would have come across an annoying problem. That annoying problem is making sure that the URL is correctly encoded.

At first glance it would seem that the Cocoa Frameworks do this for you, and you would be right …. well kind of.

The issue is that by default most of these methods leave characters such as & = ? within a URL, as they are strictly speaking valid. The problem is that these characters have special meanings in a GET request, and will more than likely make your request in valid.

Luckily there is a function in Core Foundation that helps:

1
2
3
4
5
6
7
CFStringRef CFURLCreateStringByAddingPercentEscapes (
   CFAllocatorRef allocator,
   CFStringRef originalString,
   CFStringRef charactersToLeaveUnescaped,
   CFStringRef legalURLCharactersToBeEscaped,
   CFStringEncoding encoding
);

What makes this function useful, is the legalURLCharactersToBeEscaped parameter. This will escape legal characters such as & ? = if they are supplied. This allows you to escape parameters using the following code.

1
2
 
CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)parameter, NULL, CFSTR(":/?#[]@!$&’()*+,;="), kCFStringEncodingUTF8)

An example of when to use this, is Twitters Update status API. You can find that here http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses%C2%A0update

To update your status to the following:

This is my status

You would need to post up the following URL:

http://twitter.com/statuses/update.xml?status=This%20is%20my%20status

As this is such a common problem of mine, I have created a category on NSURL. This allows you to pass in a base URL and a parameters dictionary.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 
+ (NSURL *)URLWithBaseString:(NSString *)baseString parameters:(NSDictionary *)parameters{
 
NSMutableString *urlString = [NSMutableString string];
 
//The URL starts with the base string
[urlString appendString:baseString];
 
NSString *escapedString;
 
NSInteger keyIndex = 0;
 
for (id key in parameters)
 {
 
//First Parameter needs to be prefixed with a ? and any other parameter needs to be prefixed with an &
if(keyIndex ==0)
{
escapedString = (NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
 (CFStringRef)[parameters valueForKey:key],
 NULL,
 CFSTR(":/?#[]@!$&’()*+,;="), 
kCFStringEncodingUTF8);
 
[urlString appendFormat:@"?%@=%@",key,escapedString];
[escapedString release];
}else{
 
escapedString = (NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 
(CFStringRef)[parameters valueForKey:key],
 NULL, 
CFSTR(":/?#[]@!$&’()*+,;="),
 kCFStringEncodingUTF8);
 
[urlString appendFormat:@"&%@=%@",key,escapedString];
[escapedString release];
 
}
 
keyIndex++;
}
 
return [NSURL URLWithString:urlString];
 
}

Using a parameters dictionary keeps the code nice and clean, but beware, to use the category method above you still have to make sure that your keys, and the base URL are correctly encoded (no spaces or invalid characters !!!!!).

As we now have a category method to do all the hard work for us, to create the Twitter URL you just need to do the following:

1
2
3
4
5
NSString *baseString=@"http://twitter.com/statuses/update.xml";
 
NSDictionary *dictionary=[NSDictionary dictionaryWithObjectsAndKeys:@"This is my status",@"status",nil];
 
NSURL *url=[NSURL URLWithBaseString:baseString parameters:dictionary];

And thats it. Obviously this category can be used for things other than twitter ….. if you really want to.

Reopening an application’s main window by clicking on the Dock Icon

1

When building Mac applications, Apple usually takes care of most of the default behaviours for you. One thing that Mac applications don’t do by default is, reopening the applications main window (if it has been closed), when the dock icon is pressed.

Although this information is very hard to find in the documentation, but is actually very easy to. The method you need to find is:

1
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag;

This is an optional delegate method that your AppDelegate can choose to implement, and is called when the user presses your application’s dock icon. The bool flags indicates whether the application has any visible windows. To reopen your application’s main window, you need to have a pointer to it (In the example below assume that it is defined as NSWindow *window; in the header file). If you do have a pointer to then you simple need to implement the code below.

1
2
3
4
5
6
7
8
 
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag{
 
	if(flag==NO){
		[window makeKeyAndOrderFront:self];	
	}
	return YES;	
}

It is as simple as that.

NSUserDefaults (Preferences)

0

Not everybody likes their applications to behave in the same way, and this is why the majority of Mac and iPhone applications have preferences. The default way to handle these preferences is using the class NSUserDefaults.

NSUserDefaults are stored on the file system as .plist, which is simply an XML document. The way you access NSUserDefaults programatically is very much like accessing an NSMutableDictionary, that is by using keys.

Setting User Defaults

NSUserDefaults can be a bool, float, integer or an object. So if you wanted to set the autosave option (which is a BOOL) for your application to be YES, you would write:

[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"AutoSave"];

Moreover if you wanted to set the person’s name to ObjColumnist you would write:

[[NSUserDefaults standardUserDefaults] setObject:@"ObjColumnist" forKey:@"PersonName"];

Reading User Defaults

Reading the user defaults is just as easy as setting them. If we wanted to retrieve the 2 values we stored above, you would simply write:

NSString *name = [ [NSUserDefaults standardUserDefaults] stringForKey:@"PersonName"];
BOOL autoSave =  [ [NSUserDefaults standardUserDefaults] boolForKey:@"AutoSave"];

You should also notice that there is a convenience method for retrieving a string for a key, even though we set it as an object.

It is also important to be aware that if you attempt to retrieve a numeric value such as an integer, integerForKey: for a non existent key, you will get the value 0. This is obviously an issue if 0 would trigger a certain preference in you application.

Setting the default user defaults

So you can now set and read the user defaults, but how do you assign their default values ?

The answer is registerDefaults:

This method is usually called in the initialize (class) method of a given application’s AppController. The parameter for this method is an NSDictionary. The code below sets the default preference for the AutoSave option to YES, and the person’s name to @”unknown”.

NSMutableDictionary *defaults=[NSMutableDictionary dictionary];
 
[defaults setObject:[NSNumber numberWithBool:YES] forKey:@"AutoSave"];
[defaults setObject:@"unknown" forKey:@"PersonName"];
 
[[NSUserDefaults standardUserDefaults] registerDefaults: defaults];

One thing that Cocoa does for you automatically without needing any extra code, is that it only saves to the .plist the values that are different to the defaults values, that were registered using registerDefaults: . This means that if the user does not change any of their default preference settings, there will no be a preference file created.

Note: The code above just stores the preference for the AutoSave option, you still have to create the code to manage the saving of data yourself.

Helper Objects (Delegate and DataSource)

6

Helper Objects are used throughout Cocoa and CocoaTouch, and usually take the form of a delegate or dataSource. They are commonly used to add functionality to an existing class without having to subclass it.

In software engineering, the delegation pattern is a technique where an object outwardly expresses certain behaviour but in reality delegates responsibility for implementing that behavior to an associated object in an Inversion of Responsibility. The delegation pattern is the fundamental abstraction that underpins composition (also referred to as aggregation), mixins and aspects.

http://en.wikipedia.org/wiki/Delegation_pattern

The most common use of helper objects in iPhone development is when using UITableViews. When you instantiate a UITableViewController this class is automatically assigned to be the delegate and dataSource of the table view it holds.

self.tableView.delegate=self;
self.tableView.dataSource=self;

The UITableView then calls the appropriate delegate method when it needs information, such as:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

This ask the delegate, what is the height for the row at a given index path, so in your UITableViewController (the delegate) you would write the following, if you wanted the row to be 44 pixels high (the default).

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
 
      return 44;
}

Writing your own delegate.

Most delegates are declared as a protocol, so the compiler knows that the delegate implements the required methods.

Example:

You have created a subclass of UITextView (e.g. OBCTextView), that you use in your application to enter both Tweets and SMS. You want to use the same class for both, BUT tweets have a character limit of 140 and SMS have a character limit of 160 (we will pretend that we are still in the 90s).

So we need to create a delegate that asks for the character limit.

 
- (NSInteger)charachterLimitForTextView:(OBCTextView *)textView;

As mentioned before this should be declared as a protocol

@protocol OBCTextViewDelegate
 
- (NSInteger) charachterLimitForTextView: (OBCTextView *)textView;
 
@end

The OBCTextView would call this method like so:

 
- (void)askDelegateForCharachterLimit{
 
NSInterger charachterLimit = [delegate charachterLimitForTextView:self];
 
//Do something with character limit
 
}

In our SMS view controller we would declare that we implement the delegate protocol.

 
@interface OBCSMSViewController : UIViewController < OBCTextViewDelegate > {
 
}
 
@end

And then in the implementation file you would implement the following method

 
- (NSInteger) charchterLimitForTextView: (OBCTextView *)textView{
       return 160;
}

This method is required for OBCTextView to work so we should also add the key word @required to the protocol

@protocol OBCTextViewDelegate
 
@required
- (NSInteger)charchterLimitForTextView:(OBCTextView *)textView;
 
@end

Optional methods

In your delegate, you may also want to implement optional methods. So for this example we will ask for the text color. You can specify that a method is optional using @optional.

 
@protocol OBCTextViewDelegate
 
@required
- (NSInteger)charachterLimitForTextView:(OBCTextView *)textView;
 
@optional
- (UIColor *)textViewColorForTextView:(OBCTextView *)textView;
 
@end

As it is optional the delegate class (helper object), does not have to implement it. If it does not implement it, and we attempt to call it, the application will crash. So how do we know if we should call the method or not ? The answer is respondsToSelector.

respondsToSelector allows you to ask an object at run time, if it implements a given selector. So for our example:

 
- (void)getTextColor
{
if( [delegate respondsToSelector: @selector(textViewColorForTextView:)] )
{
UIColor *textColor = [delegate textViewColorForTextView:self];
//Do something with the text color
}
}

if your class wants to return a textview color, then you simply implement the method.

 
- (NSInteger)textViewColorForTextView:(OBCTextView *)textView{
       return [UIColor redColor];
}

So that finishes off this post on helper objects, and how you can create your own. As always this example was a simple one to make it easy to follow. You could probably implement the above using setter methods.

Go to Top