INTERMEDIATE OBJECTIVE-C
CocoaShops
Curtis Herbert
Carl Leiby
Kotaro Fujita
Mike Zornek
@parrots
@carlism
@wild37
@zorn
Slide 2
Slide 2 text
THE BASICS
Slide 3
Slide 3 text
HISTORY OF OBJ-C
• 1983 - C + Smalltalk come together as a C pre-compiler
• 1988 - NeXT licensed the language
• 1996 - Apple buys NeXT as foundation for OS X (“Rhapsody”)
• 2006 - Objective-C 2.0
• 2008 - iPhone SDK
Slide 4
Slide 4 text
THE IN THE ROOM
Swift is the future, right?
Slide 5
Slide 5 text
THE BASICS
CORE LANGUAGE FEATURES
Slide 6
Slide 6 text
C PRIMITIVES
FLOAT
DOUBLE
VOID
CHAR
BOOL
INT
Slide 7
Slide 7 text
int myAge = 6;
myAge = myAge + 6;
int alsoMyAge = myAge;
C PRIMITIVES
Slide 8
Slide 8 text
WHERE THINGS GET FUN:
OBJ-C IS A DYNAMIC RUNTIME
A quick detour to the deep end
Slide 9
Slide 9 text
[tableView reloadData];
Send the message “reloadData” to the object “tableView”
objc_msgsend(tableview, @selector(reloadData));
MESSAGE SENDING
Slide 10
Slide 10 text
“Objective-C decides which method implementation to call right before
doing so (during runtime). The idea is that the connection between the
name of a method and the implementation is dynamic. C++ for example
does this during compile time.”
Slide 11
Slide 11 text
AN EXAMPLE OF THIS VOODOO
UIView *myNewView = [[UIView alloc] init];
object_setClass(myNewView, [MyOtherClass class]);
(this isn’t a common thing to do, don’t worry)
Slide 12
Slide 12 text
-[NSArray objectForKey:]: unrecognized selector sent to instance 0x102301c40
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NSArray objectForKey:]: unrecognized selector sent to instance
0x102301c40'
Slide 13
Slide 13 text
CLASS
OBJ-C PRIMITIVES
SEL
ID NIL
Slide 14
Slide 14 text
OBJ-C PRIMITIVES
SEL CLASS
ID
id name = @“Curtis”;
id date = [NSDate new];
NIL
Slide 15
Slide 15 text
OBJ-C PRIMITIVES
SEL CLASS
ID
- (id) someMethod;
NIL
Slide 16
Slide 16 text
OBJ-C PRIMITIVES
SEL CLASS
ID
SEL mySelector = @selector(update);
[self performSelector:mySelector];
NIL
Slide 17
Slide 17 text
OBJ-C PRIMITIVES
SEL CLASS
ID
SEL mySelector = @selector(update);
if ([self respondsToSelector:mySelector]) { }
NIL
Slide 18
Slide 18 text
OBJ-C PRIMITIVES
SEL CLASS
ID
SEL mySelector = @selector(updateName:);
[self performSelector:mySelector withObject:@“Joe”];
NIL
Slide 19
Slide 19 text
OBJ-C PRIMITIVES
SEL CLASS
ID
SEL mySelector = NSSelectorFromString(@“myMethod”);
[self performSelector:mySelector];
NIL
Slide 20
Slide 20 text
OBJ-C PRIMITIVES
SEL CLASS
ID
Class targetClass = [NSDate class];
if ([myObject isKindOfClass:targetClass]) …
NIL
Slide 21
Slide 21 text
OBJ-C PRIMITIVES
SEL CLASS
ID
myObject = nil;
NSString *name = [myObject showName];
NIL
Slide 22
Slide 22 text
OBJ-C DIRECTIVES
• Instructions to the compiler
• @IBOutlet, @property, @class, etc
• @“string”, @[@“string1”], @{@“key” : @“value”}
Slide 23
Slide 23 text
HANDS-ON #1
Slide 24
Slide 24 text
CORE LANGUAGE FEATURES
Deep breaths - back to more familiar territory
CONVENTIONS - ACCESSORS
setFont: and font
not
setFont: and getFont
Slide 38
Slide 38 text
CONVENTIONS - CLARITY
Code Commentary
insertObject:atIndex: Good.
insert:at: Not clear; what is being inserted? what does “at” signify?
removeObjectAtIndex: Good.
removeObject: Good, because it removes object referred to in argument.
remove: Not clear; what is being removed?
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/
NamingBasics.html#//apple_ref/doc/uid/20001281-BBCHBFAH
Slide 39
Slide 39 text
CONVENTIONS - DESCRIPTIVE
Code Commentary
destinationSelection Good.
destSel Not clear.
setBackgroundColor: Good.
setBkgdColor: Not clear.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/
Articles/NamingBasics.html#//apple_ref/doc/uid/20001281-BBCHBFAH
Slide 40
Slide 40 text
CONVENTIONS - PREFIXING
• Class Prefix — UIColor,
NSString, CLLocation, etc
• Apple uses 2-letter prefix
• Prefix your classes with your initials
Prefix Cocoa Framework
NS Foundation
NS Application Kit
AB Address Book
IB Interface Builder
UI UIKit
Slide 41
Slide 41 text
HANDS-ON #2
Slide 42
Slide 42 text
POINTERS
Not the tips and tricks kind
Slide 43
Slide 43 text
- (void)myMethod {
int a = 10;
}
C primitives only exist in memory as long as they’re in scope.
The memory for a is gone after the method returns.
Slide 44
Slide 44 text
int a = 10;
int b = a;
b = 20;
C primitives are passed by making copies.
10
➡️
Slide 45
Slide 45 text
int a = 10;
int b = a;
b = 20;
C primitives are passed by making copies.
10 10
➡️
Slide 46
Slide 46 text
int a = 10;
int b = a;
b = 20;
C primitives are passed by making copies.
10 20
➡️
Slide 47
Slide 47 text
int a = 10;
[self myAdder:a];
a = 20;
C primitives are passed by making copies.
10
- (void)myAddder:(int)c {
adder += 40;
}
➡️
Slide 48
Slide 48 text
int a = 10;
[self myAdder:a];
a = 20;
C primitives are passed by making copies.
10 10
- (void)myAddder:(int)c {
adder += 40;
}
➡️
Slide 49
Slide 49 text
int a = 10;
[self myAdder:a];
a = 20;
C primitives are passed by making copies.
10 50
- (void)myAddder:(int)c {
adder += 40;
}
➡️
Slide 50
Slide 50 text
int a = 10;
[self myAdder:a];
a = 20;
C primitives are passed by making copies.
20
- (void)myAddder:(int)c {
adder += 40;
}
➡️
Slide 51
Slide 51 text
Objects don’t work this way in Objective-C.
They use pointers.
Slide 52
Slide 52 text
NSNumber *myNumber = [[NSNumber alloc] init];
NSNumber
A pointer is a variable whose value is the address of another
variable.
Slide 53
Slide 53 text
NSNumber *myNumber = [[NSNumber alloc] init];
A pointer is a variable whose value is the address of another
variable.
NSNumber
*
Slide 54
Slide 54 text
NSNumber *myNumber = [[NSNumber alloc] init];
NSNumber
*5
A pointer is a variable whose value is the address of another
variable.
Slide 55
Slide 55 text
*0
NSNumber *myNumber;
The nil value means “this instance reference isn’t pointing to any
instance.”
Slide 56
Slide 56 text
*0
NSNumber *myNumber = nil;
if (myNumber) {
//do something if not nil
}
nil is equivalent to 0
IF YOU CREATE, YOU RELEASE
- (void)shareActivity {
NSDate *today = [[NSDate alloc] init];
//do some stuff with the date
[today release];
}
Slide 75
Slide 75 text
AUTORELEASE TO TRANSFER
OWNERSHIP
- (NSDate *)todaysDate {
NSDate *today = [[NSDate alloc] init];
//do some stuff with the date
return [today autorelease];
}
2014-03-30 02:30:36.172 tradeRumors[3997:20b]
*** -[GameLayer update]: message sent to
deallocated instance 0x59bf670
EXEC_BAD_ACCESS
Slide 79
Slide 79 text
PROFILING FOR LEAKS
⌘I
Slide 80
Slide 80 text
No content
Slide 81
Slide 81 text
HANDS-ON #4
Use NSLog(@"%lu", (unsigned long)[self retainCount])
to print an object’s current reference count
Slide 82
Slide 82 text
AUTOMATIC REFERENCE COUNTING
• Added in 2011
• Compiler automatically adds these retain/release calls
• Different than garbage collection (which is at runtime)
• Didn’t solve all the retain-related issues…
weak - does not increase the
reference count
atomic - creates a lock in
setters/getters
readonly - only creates a
getter for the property
copy - creates a copy instead of
retaining original object
strong - increases the
reference count
nonatomic - does not lock,
better performance
readwrite - creates setter
and getter
assign - similar to weak, used
for primitives
@property PCHActivityMonitor *monitor; _monitor
@property PCHActivity *activity; _activity
SYNTHESIZED IVARS
Property definition ivar name
In general though, avoid accessing ivars, always use self.property.
Use ivars in custom setters and gettings.
Slide 90
Slide 90 text
HANDS-ON #5
You can use NSLOG(@“%@“, object) again to verify unique
copies
@interface UITableView : UIScrollView
...
@property (nonatomic, weak) id dataSource;
@property (nonatomic, weak) id delegate;
...
Slide 125
Slide 125 text
Use this when you want two-way communications between
classes, but you don’t want to have to hard-code references.
Great for reusability / being able to swap out implementations.
@interface PCHServerAPI : NSObject
@property (nonatomic) NSUInteger downloadCount;
@property (nonatomic) BOOL downloading;
@end
WHAT IF?
“Hey, tell me if these change.”
Slide 129
Slide 129 text
KEY-VALUE OBSERVING (KVO)
• Listen for changes for a given key-path
• One-way: doesn’t need to know about subscribers
• Ad-hoc: no formal contract (protocol)
• Automatic
• Limitless subscribers
[self.serverAPI addObserver:self
forKeyPath:@“downloadCount”
options:0
context:nil];
...
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqualToString:@"downloadCount"]) {
//do something with the change
}
}
Slide 133
Slide 133 text
NSStringFromSelector(@selector(downloadCount));
A FEW IMPROVEMENTS
Slide 134
Slide 134 text
A FEW IMPROVEMENTS
static void * MyContext = &MyContext;
...
- (void)observeValueForKeyPath:(NSString *)keyPath... {
if (context == MyContext) {
} else {
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
}
Slide 135
Slide 135 text
UNSUBSCRIBING - A PAIN
@try {
[self.server removeObserver:self
forKeyPath:NSStringFromSelector(@selector(downloadCount))
context:MyContext];
}
@catch (NSException * __unused exception) {}
• Can’t check if you’re a subscriber
• Will crash if you try to unsubscribe when not already subscribed
CLEANUP - USE CONSTANTS
[[NSNotificationCenter defaultCenter]
postNotificationName:PCHServerDownloadStartNotification
object:nil
userInfo:@{PCHServerDownloadCountKey: @(4)}];
Slide 152
Slide 152 text
Use this when you want to allow multiple objects to be notified
when something happens without needing any link between the
objects.
Slide 153
Slide 153 text
HANDS-ON #10
• setDownloads is a great place to send a notification (if
conditions are met)
• you’ll need to use [NSNumber numberForBOOL:] to send
bool values in the user info dictionary, and
[number boolValue] to get it on the other side
• Exceptions exist in Objective-C, but are expensive
• Instead return a successful BOOL if no return type needed, or nil if
an object is expected.
• Use an NSError parameter with information about the error
(same as you would use an exception to bubble up information).
** pointer to a pointer
& location in memory
A POINTER TO A POINTER?
* pointer to an object
Slide 162
Slide 162 text
NSError *error = nil;
A POINTER TO A POINTER?
*5 NSError
if (error) {
*error = [NSError errorWithDomain:@“...” code:1 userInfo:nil];
}
}
-(BOOL)save:(NSError**)error {
BOOL success = [myContext save:&error];
Slide 163
Slide 163 text
A LITTLE MORE ON NSERROR
[NSError errorWithDomain:domain code:code userInfo:userInfo];
Domain - reverse DNS, most likely the same as your app ID
(“com.consumedbycode.slopes”, for example)
Code - you pick these and define their meanings. Internal to app logic.
UserInfo - can use to pass back a dictionary of values to the handler.
Usually a description using NSLocalizedDescriptionKey.
Slide 164
Slide 164 text
extern NSString * const PCHSlopesErrorDomain;
extern NSString * const PCHSlopesErrorUnknownTypeDescription;
extern int const PCHSlopesErrorUnknownTypeCode;
NSString * const PCHSlopesErrorDomain =
@“org.phillycocoa.slopes”;
NSString * const PCHSlopesErrorUnknownTypeDescription =
@"File type for export unknown.”;
int const PCHSlopesErrorUnknownTypeCode = 100;
CLEANUP - USE CONSTANTS
Slide 165
Slide 165 text
HANDS-ON #11
Slide 166
Slide 166 text
A FEW MORE LANGUAGE FEATURES
Slide 167
Slide 167 text
CATEGORIES
• A category allows you to add methods to an existing class without
subclassing it or needing to know any of the details of how it's
implemented.
• Effects all instances of that class within the application.