Paul Calnan
Published August 27, 2014

I use a lot of TextExpander snippets when doing Objective-C development. I really like Objective-C, but it can be pretty verbose at times. If I find myself typing the same thing repeatedly, I make a new snippet for it.

The snippets make extensive use of Xcode placeholder tokens. For example:

[NSString stringWithFormat:@"<#format string#>", <#args#>]

This will give you two placeholder "bubbles"; one for format string and the other for args. You can tab between the bubbles and replace them with whatever you need in that place.

Initializers

I use ;init to insert a default initializer:

- (instancetype)init
{
    if ((self = [super init]))
    {
        %|
    }
    return self;
}

Notice the use of %| which defines the cursor location after the snippet is expanded.

I also use ;iinit to insert an initializer body (iinit for Inside Init):

    if ((self = [super init]))
    {
        %|
    }
    return self;

That's useful for writing initializers with parameters. It's indented an extra four spaces since it's going inside the method body.

Default Description Implementation

I use ;desc to generate a -description method that behaves like the default in NSObject. I can then build on it from there.

- (NSString *)description
{
    return [NSString stringWithFormat:@"<%@: %p>", NSStringFromClass([self class]), self];
}

UIViewController View Methods

;vwa generates a -viewWillAppear:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    %|
}

;vwd generates a -viewWillDisappear:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    %|
}

;vda generates a -viewDidAppear:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    %|
}

;vdd generates a -viewDidDisappear:

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    %|
}

Properties

Variations for readonly, copy, strong, weak, and assign:

;pnra expands to:

@property (nonatomic, readonly, assign)

;pnrc expands to:

@property (nonatomic, readonly, copy)

;pnrs expands to:

@property (nonatomic, readonly, strong)

;pnrw expands to:

@property (nonatomic, readonly, weak)

;pna expands to:

@property (nonatomic, assign)

;pnc expands to:

@property (nonatomic, copy)

;pns expands to:

@property (nonatomic, strong)

;pnw expands to:

@property (nonatomic, weak)

The Strong-Self / Weak-Self Dance

;ws expands to:

__weak typeof(self) weakSelf = self;

;ss expands to:

__strong typeof(weakSelf) strongSelf = weakSelf;

Private Read-Write Property Declarations

Say you have a public interface for a class, like this:

@interface SomeClass : NSObject
@property (nonatomic, readonly, copy) NSString *someString;
@property (nonatomic, readonly, copy) NSDictionary *someDictionary;
@end

If you want to generate a private declaration, simply copy the interface to the pasteboard and run ;dprivate. This is a shell script snippet, that performs the following:

#!/bin/sh
pbpaste | sed -e 's/ : .*$/ ()/' -e 's/, readonly//' | grep -v '^[-+]' | grep -v '^$'

Using the example above, this would output:

@interface SomeClass ()
@property (nonatomic, copy) NSString *someString;
@property (nonatomic, copy) NSDictionary *someDictionary;
@end

Mark Pragmas

;mark expands to:

#pragma mark -

;public expands to:

#pragma mark - Public Methods

;private expands to:

#pragma mark - Private Methods

Declare and Initialize an Object using the Default Initializer

;new uses a fill-in for the type name and variable name:

%filltext:name=typename% *%filltext:name=varname% = [%filltext:name=typename% new];

If you enter NSMutableArray and array, this will yield:

NSMutableArray *array = [NSMutableArray new];

Key-Value Observing Done Right

I've long since lost where I got these, but it's the correct way to register for KVO notifications.

Declare a context variable static to the source file with ;kvocontext:

static void *kKVOContext = &kKVOContext;

Register for KVO notifications in the initializer, viewWillAppear, etc. with ;kvoadd:

[<#(id)#> addObserver:self forKeyPath:<#(NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:kKVOContext];

Deregister from KVO notifications in dealloc, viewWillDisappear, etc. with ;kvoremove:

[<#(id)#> removeObserver:<#(NSObject *)#> forKeyPath:<#(NSString *)#> context:kKVOContext];

And, finally, declare the KVO notification hander with ;kvomethod:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context != kKVOContext)
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    }

    if ([keyPath isEqualToString:<#(NSString *)#>])
    {
        %|
    }
}

Documents Directory

I used to have to look this up whenever I needed to use the documents directory. Now I use ;document:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *<#path#> = [documentsDirectory stringByAppendingPathComponent:<#filename#>];

The final NSString variable is the full path to a file in the documents directory.

Common Type Names

;nsa expands to NSArray

;nsd expands to NSDictionary

;nss expands to NSString

;nsma expands to NSMutableArray

;nsmd expands to NSMutableDictionary

;nsms expands to NSMutableString

These also work with the ;new snippet, above.

Miscellaneous

Reference the default NSNotificationCenter using ;dnc:

[NSNotificationCenter defaultCenter]

Make a new NSString by calling -stringWithFormat: with ;swf. The %key:tab% at the end highlights the format string placeholder:

[NSString stringWithFormat:@"<#format string#>", <#args#>]%key:tab%

Make a constant string whose value is equal to the variable name with ;cstr:

NSString *const %fill:name% = @"%fill:name%";

Xcode Paths

These are useful in the Terminal or in the Go to Folder dialog in the Finder.

;iossdks expands to:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs

;osxsdks expands to:

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs

;simulator expands to:

~/Library/Application\ Support/iPhone\ Simulator

;archives expands to:

~/Library/Developer/Xcode/Archives

;deriveddata expands to:

~/Library/Developer/Xcode/DerivedData