Objective-C Notes

This is my notes when learning Objective-C. OC stands for Objective-C hereafter.

Prepare

Install XCode with command line tools. (I feel OC very different on other OS ... even no Foundation?)

1
sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer

As an IDE hater ...

1
2
alias occ='gcc -framework Foundation'
occ *.m

Comparing to C++:

  • #import is the #pragma once version of #include, but tend to compile faster since #include still need compiler to read the same header.
  • -framework is an improvement over the traditional trinity: -I, -L, -l.
  • Method invocation syntax is supposed to make me uncomfortable for a while.

OC method lookup is slower than C++ vtable queries, but most pointers are cached (right) after a lookup, so it's faster than vtable. Cached pointers are still a little bit slower than C++ if C++ knows the target method at compile time. It's like run time optimization vs compile time optimization between the two. However however, since recent C++ compilers are doing more dynamic optimizations, they are not so different in fact ...

Syntax

  • id can be anything.
  • BOOL can be YES, NO, TRUE or FALSE.
  • SEL see @selector in the following.
  • nil is NULL.
  • Nil is the nil for a class object.

@interface .. @end, @implementation .. @end for declaring and implement classes.

Header for the interface: .h

1
2
3
4
5
6
@interface ClassName : SuperClass {
// instance vars
}
// properties
// methods
@end

Module for the implementation: .m

1
2
3
4
@implementation ClassName
// synthesize properties
// methods
@end

@property is like getter / setter macros

1
@property NSString* (attr1, attr2) name;

attr is the combination of the following entries:

attr meaning
retain add ref counter on assign by calling retain
assign normal assign (default)
copy copy on assign
nonatomic faster, maybe not thread safe
readwrite getter and setter (default)
readonly getter only
getter
setter

1
2
3
4
5
6
// example
o.someName = a;
o.someName
// are shorts for:
[o setSomeName:a];
[o someName];

@synthesize / @dynamic generate / hand-craft implementation of the property

1
2
3
4
5
6
@synthesize name;
@synthesize name = instance_var_name;
@dynamic addr;
-(NSString*) addr {...}
-(void) setAddr:(NSString*) a {...}

@synthesize can be used to multiple attributes at one line.

1
@synthesize name, content, address;

@class declare a class for existence without knowing its structure.

For example, have WebView without importing <WebKit/WebKit.h> to make header less-dependant.

1
2
3
4
@class WebView;
@interface BrowserController : NSObject {
WebView *myWebView;
}

But in implementation you have to really import <WebKit/WebKit.h> for the class.

@protocol .. @end, @optional, @required declares the methods shall be implemented.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@protocol Foo
@optional
-(BOOL) hello;
@end
@protocol Bar
@required
-(void) world;
@end
// not c++ template !
@interface Bas : NSObject<Foo, Bar>
...
@end

@public, @private, @protected sections only for instance variables, inheritance (always like C++ public) can not be tagged with these scope modifiers.

@try, @catch, @throw, @finally for exception handling

1
2
3
4
5
6
7
8
9
10
@try{
@throw [[MyException alloc] init];
} @catch (MyException* e) {
...
} @catch (NSException* e) {
...
@throw // here means re-throw
} @finally {
...
}

@synchronized modifier for your thread-critical section.

@encode returns const char*. It's for the purpose of interoperability. @encode(X) can be applied to data types, protocols, classes, methods. It's a good way to see the internal representation. Format in [3].

@selector is "a pointer to a method", its type is SEL. Handy for generic algorithms.

1
2
3
SEL sel = @selector(readDocumentation:);
[o respondsToSelector:sel]
[o performSelector:sel withObject:a];

Create selector from string:

1
NSSelectorFromString(@"haha");

@defs copies the instance variables of a class.

1
2
3
struct InterfaceAsStruct {
@defs(AnInterface);
} *interfaceAsStruct;

Methods

1
2
3
4
// decl / impl
-(return_type) msg1:(type1)param1 msg2:(type21)param21,(type22)param22
// invoke
[o msg1:param1 msg2:param21,param22]
  • - for instance method.
  • + for class method.
  • self for current object, the hidden parameter, can be changed.
  • super for parent class.
  • NO this.

A method call

1
[myWebView searchFor:myString direction:YES caseSensitive:NO wrap:YES]

is converted at runtime to this function call:

1
2
objc_msgSend(myWebView, searchFor:direction:caseSensitive:wrap:,
myString, YES, NO, YES)

Memory Management

initializer:

  • should return self or nil. A call to super init and nil check is necessary.
  • method name should init with init
1
2
3
4
5
6
7
8
-(id) initWhatEver ... {
// use [[[self class] alloc] init] for dynamic class here
if (self = [super init]) {
...
return self;
}
return nil;
}

destructor:

1
2
3
4
-(void) dealloc {
...
[super dealloc];
}

alloc initializes all the bits to 0, so the pointers are set to nil. init is NOT optional.

1
2
Klass* obj1 = [[Klass alloc] init];
[obj release]

to use reference counting:

1
2
3
4
5
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// ...
[pool drain];
// ...
[pool release];

autorelease is like shared_ptr in Boose but not auto_ptr in STL. The nearest pool on stack is used.

1
2
3
4
-(Point*) add:(Point*)p1 and:(Point*)p2 {
Point* result = [[Point alloc] initWithX:(p1.x + p2.x) andY:(p1.y + p2.y)];
return [result autorelease];
}

It's legal to [nil release], but multiple autorelease will cause segfault on pool releasing.

A retain increases counting by 1, and a release decreases it.

When ARC(automatic reference counting) enabled, you can't call autorelease by hand.

Data Structures

  • NSArray, NSMutableArray
  • NSSet, NSMutableSet
  • NSDictionary, NSMutableDictionary
  • NSHashTable as hash table using weak references

Fast enumeration:

1
2
3
for(NSString obj in container) {
...
}

Using selector to perform computation for every element: makeObjecsPerformSelector

1
2
NSArray* a = [NSArray arrayWithObjects:o1, o2, o3];
[a makeObjecsPerformSelector:@selector(doSomething:) withObject:@"foo"]

IMP caching: use _getMethodImplementation on class and get the C pointer and use it many times to save method lookups.

Key-value coding: access data member by its name.

1
2
3
4
[foo valueForKey:@"bar"]
[foo valueForKeyPath:@"baz.xip"]
[foo setValue:1 forKey:@"bar"]
[foo setValue:1 forKeyPath:@"baz.xip"]

Accessing rule for key-value coding:

  1. getBar:bar:isBar:
  2. if 1. fails and class returns YES for accessInstanceVariablesDirectly, try to read _bar_isBarbar_isBar
  3. if 2. fails valueForUndefinedKey is called, else an exception is thrown.

Dictionary

1
2
3
4
id dict = [[NSDictionary alloc] initWithObjectsAndKeys:
@"k1", "v1",
@"k2", "v2"];
[dict objectForKey:@"k1"];

Using immutable dictionary

1
2
3
id dict = [[NSMutableDictionary alloc] initWithCapacity: 5];
[dict setObject:@"obj" forkey:@"obj"]
[dict removeObjectForKey:@"key"];

Grand Central Dispatch

  • Block type void (^block)(size_t).
  • Typedef typedef int (^BT)();.
  • Block syntax 1 ^{ ... }.
  • Block syntax 2 ^(p1, p2){ ... }.
  • Captured variables are read-only

Use __block to declare block-accessible vars

1
2
3
__block int i = 1;
BT bt = ^{ return i++; };
bt();

Protocol Message Qualifiers

in, out, inout, bycopy, byref, oneway

oneway is asynchronous, the result is not immediately expected, hence it must return void.

1
-(oneway void) giveMeMoney:(bycopy out id*)anObject;

inout by default, except const qualifiers.

"Value" Classes

Many classes are designed to contain a hidden cluster of sub-classes, exposing only factory methods.

If an object that is an NSValue that holds a "POD", then it's immutable and no need to hand-release it.

Delegate And Outlet And Action

Being delegated class or protocol:

1
2
- (id)delegate;
- (void)setDelegate:(id)newDelegate;

Deleted

A Data Source is a delegate that provides data.

An outlet is a property of an object that references another object. The reference is archived through Interface Builder. The connections between the containing object and its outlets are reestablished every time the containing object is unarchived from its nib file. The containing object holds an outlet declared as a property with the type qualifier of IBOutlet and a weak option.

1
2
3
4
5
6
7
8
9
@interface AppController : NSObject {
NSArray *keywords; // can ignore
}
@property (weak) IBOutlet NSArray *keywords;
@end
@implemented AppController
@synthesize keywords;
@end

With some compiler magic, you can create your property without declaring the instance variable when targeting 64-bit.

IBAction is equal to void, but hints XCode to make it connectable in Interface Builder.

1
- (IBAction)actionName:(id)sender

Introspection

1
2
3
4
5
[o class] == [p superclass]
[o isKindOfClass: k] // kind_of?
[o isMemberOfClass: k] // is_a?
[o respondsToSelector: s]
[o conformsToProtocol: p]

Object Comparison

hash and isEqual.

These names are suggested as a convention in cocoa:

isEqualToString, isEqualToTimeZone, isEqualToWidget (check name and data).

Log

1
NSLog(@"%@s %@", astring, anobject);

Grouping Methods In XCode Jumpbar

#pragma mark - adds a separator, and #pragma mark <otherwords> adds a group name.

1
2
#pragma mark -
#pragma mark Hello world

An Interface-Builder-Centralised View

When a xib or nib file is unarchived, objects declared in it are allocated and connected like a dependency-injection container. We replace void with IBAction in -(void)action(id)sender, to make it an action, so that interface builder knows it and thus connectable.

Any object can be added into the nib file, especially delegates / controllers. If a control has a delegate attribute (outlet), you can drag and connect to a delegate that have been added into the nib. If an object, especially a controller, needs to visit controls declared in the nib, declare outlets in the controller and connect them.

References

[1] OC Cheatsheet
http://www.raywenderlich.com/downloads/RW-Objective-C-Cheatsheet.pdf

[2] From C++ To OC
http://chachatelier.fr/programmation/fichiers/cpp-objc-en.pdf

[3] OC Reference
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/ObjC.pdf

[4] OC Concepts
https://developer.apple.com/library/mac/documentation/General/Conceptual/CocoaEncyclopedia/CocoaEncyclopedia.pdf

Comments