working effectively with objective-c on iphone...

Post on 06-Mar-2018

217 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Blaine GarstWizard of Runtimes

Working Effectively withObjective-C on iPhone OS

2

Blaine GarstWizard of Runtimes

Working Effectively withObjective-C on iOS 4

3

Objective-C is the language of Cocoa Touch. Take an in-depth working tour of Objective-C, from properties and memory management, to integrating your existing C and C++ code with Objective-C. Examine design patterns, exception models, and other important considerations. A valuable session to hone your knowledge of the language.

4

Objective-C

ExceptionsSyntax: Statements, Control Flow, Operators

Closures (ObjC: Blocks)

Primitives: Numbers, Strings

Input/OutputPlatform: Memory Management

Inheritance

Accessors

Aggregates: Structures, Objects

Interfaces (ObjC: Protocols)

Collections: Lists, Arrays, Sets, Maps

C

C++

C#Java

LISP/Scheme

OCamlHaskellErlangGo

RubyPythonJavaScriptPHPPerl

Objective-C

5

Territory

• Map and Go With What You Know■ Introduce Objective-C Terminology for Common Concepts

• Introduce Objective-C Uncommon Ideas■ Blocks■ @properties—let the compiler write your accessors!■ Categories—add behavior (methods!) to any class■ Selectors, Delegates, @optional

• Discuss Cocoa Touch Patterns■ Memory Management—Retain, Release, Autorelease■ Mutability, Class Clusters, “PLists”

6

Objective-CC

C++

ExceptionsSyntax: Statements, Control Flow, Operators

Closures (ObjC: Blocks)

7

Blocks

8

typedef void (^ALAssetsGroupEnumerationResultsBlock)(ALAsset *result, NSUInteger index, BOOL *stop);typedef void (^ALAssetsLibraryGroupsEnumerationResultsBlock)(ALAssetsGroup *group, BOOL *stop);typedef void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *asset);typedef void (^ALAssetsLibraryAccessFailureBlock)(NSError *error);typedef void (^ALAssetsLibraryWriteImageCompletionBlock)(NSURL *assetURL, NSError *error);typedef void (^ALAssetsLibraryWriteVideoCompletionBlock)(NSURL *assetURL, NSError *error);typedef void (^AudioQueueOutputCallbackBlock)(typedef void (^AudioQueueInputCallbackBlock)(- (void)exportAsynchronouslyWithCompletionHandler:(void (^)(void))handler;typedef void (^AVAssetImageGeneratorCompletionHandler)(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error);- (void)loadValuesAsynchronouslyForKeys:(NSArray *)keys completionHandler:(void (^)(void))handler;- (void)captureStillImageAsynchronouslyFromConnection:(AVCaptureConnection *)connection completionHandler:(void (^)(CMSampleBufferRef imageDataSampleBuffer, NSError *error))handler;- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;- (id)addBoundaryTimeObserverForTimes:(NSArray *)times queue:(dispatch_queue_t)queue usingBlock:(void (^)(void))block;CF_EXPORT void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) CF_AVAILABLE(10_6, 4_0); typedef void (^CMAccelerometerHandler)(CMAccelerometerData *accelerometerData, NSError *error);typedef void (^CMGyroHandler)(CMGyroData *gyroData, NSError *error);typedef void (^CMDeviceMotionHandler)(CMDeviceMotion *motion, NSError *error); void (^_callEventHandler)(CTCall *);@property(nonatomic, copy) void (^callEventHandler)(CTCall*); void (^_subscriberCellularProviderDidUpdateNotifier)(CTCarrier*);@property(nonatomic, copy) void (^subscriberCellularProviderDidUpdateNotifier)(CTCarrier*);typedef void (^EKEventSearchCallback)(EKEvent *event, BOOL *stop);- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block ;- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block ;- (void)enumerateObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block ;- (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate ;- (NSUInteger)indexOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate ;- (NSUInteger)indexOfObjectAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate ;- (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate ;- (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate ;- (NSIndexSet *)indexesOfObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate ;- (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(NSAttributedStringEnumerationOptions)opts usingBlock:(void (^)(NSDictionary *attrs, NSRange range, BOOL *stop))block ;- (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(NSAttributedStringEnumerationOptions)opts usingBlock:(void (^)(id value, NSRange range, BOOL *stop))block ;- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block ;- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id key, id obj, BOOL *stop))block ;- (NSSet *)keysOfEntriesPassingTest:(BOOL (^)(id key, id obj, BOOL *stop))predicate ;- (NSSet *)keysOfEntriesWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id key, id obj, BOOL *stop))predicate ;+ (NSExpression *)expressionForBlock:(id (^)(id evaluatedObject, NSArray *expressions, NSMutableDictionary *context))block arguments:(NSArray *)arguments ;- (id (^)(id, NSArray *, NSMutableDictionary *))expressionBlock;- (NSDirectoryEnumerator *)enumeratorAtURL:(NSURL *)url includingPropertiesForKeys:(NSArray *)keys options:(NSDirectoryEnumerationOptions)mask errorHandler:(BOOL (^)(NSURL *url, NSError *error))handler ;- (void)enumerateIndexesUsingBlock:(void (^)(NSUInteger idx, BOOL *stop))block ;- (void)enumerateIndexesWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(NSUInteger idx, BOOL *stop))block ;- (void)enumerateIndexesInRange:(NSRange)range options:(NSEnumerationOptions)opts usingBlock:(void (^)(NSUInteger idx, BOOL *stop))block ;- (NSUInteger)indexPassingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate ;- (NSUInteger)indexWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate ;- (NSUInteger)indexInRange:(NSRange)range options:(NSEnumerationOptions)opts passingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate ;- (NSIndexSet *)indexesPassingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate ;- (NSIndexSet *)indexesWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate ;- (NSIndexSet *)indexesInRange:(NSRange)range options:(NSEnumerationOptions)opts passingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate ;- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *))block ;typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);- (void (^)(void))completionBlock ;- (void)setCompletionBlock:(void (^)(void))block ;+ (id)blockOperationWithBlock:(void (^)(void))block ;- (void)addExecutionBlock:(void (^)(void))block ;- (void)addOperationWithBlock:(void (^)(void))block ;+ (NSPredicate*)predicateWithBlock:(BOOL (^)(id evaluatedObject, NSDictionary *bindings))block ;- (void)enumerateMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range usingBlock:(void (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block;- (void)enumerateObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block ;- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, BOOL *stop))block ;- (NSSet *)objectsPassingTest:(BOOL (^)(id obj, BOOL *stop))predicate ;- (NSSet *)objectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, BOOL *stop))predicate ;- (void)enumerateSubstringsInRange:(NSRange)range options:(NSStringEnumerationOptions)opts usingBlock:(void (^)(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop))block ;- (void)enumerateLinesUsingBlock:(void (^)(NSString *line, BOOL *stop))block ;+ (void)loadAchievementsWithCompletionHandler:(void(^)(NSArray *achievements, NSError *error))completionHandler;- (void)reportAchievementWithCompletionHandler:(void(^)(NSError *error))completionHandler;+ (void)loadAchievementDescriptionsWithCompletionHandler:(void(^)(NSArray *descriptions, NSError *error))completionHandler;- (void)loadImageWithCompletionHandler:(void(^)(UIImage *image, NSError *error))completionHandler;- (void)loadScoresWithCompletionHandler:(void(^)(NSArray *scores, NSError *error))completionHandler; void(^_authenticationCompletionHandler)(NSError *error);- (void)authenticateWithCompletionHandler:(void(^)(NSError *error))completionHandler;- (void)setStatus:(NSString *)status withCompletionHandler:(void(^)(NSError *error))completionHandler;- (void)loadFriendsWithCompletionHandler:(void(^)(NSArray *friends, NSError *error))completionHandler; void(^_inviteHandler)(GKInvite *);- (void)setInviteHandler:(void(^)(GKInvite *invite))inviteHandler;- (void(^)(GKInvite *))inviteHandler;- (void)createMatchForRequest:(GKMatchRequest *)request withCompletionHandler:(void(^)(GKMatch *match, NSError *error))completionHandler;- (void)findPlayersForHostedMatchRequest:(GKMatchRequest *)request withCompletionHandler:(void(^)(NSArray *players, NSError *error))completionHandler;- (void)addPlayersToMatch:(GKMatch *)match matchRequest:(GKMatchRequest *)matchRequest completionHandler:(void (^)(NSError *))completionHandler;- (void)queryPlayerGroupActivity:(NSUInteger)playerGroup withCompletionHandler:(void(^)(NSInteger activity, NSError *error))completionHandler; void(^_rateCompletionHandler)(NSError *);- (void)reportScoreWithCompletionHandler:(void(^)(NSError *error))completionHandler; void(^_playerStateUpdateHandler)(GKPlayer *, GKVoiceChatPlayerState);@property(nonatomic, copy) void(^playerStateUpdateHandler)(GKPlayer * player, GKVoiceChatPlayerState state);- (void)enumerateValuesForProperties:(NSSet *)properties usingBlock:(void (^)(NSString *property, id value, BOOL *stop))block;+ (void (^)(void))completionBlock;+ (void)setCompletionBlock:(void (^)(void))block;- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^)(void))handler ;- (BOOL)setKeepAliveTimeout:(NSTimeInterval)timeout handler:(void(^)(void))keepAliveHandler;+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion;

- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^)(void))handlerOver 100 APIs use Blocks!!!!

iOS 4 Block APIs

9

Blocks

C++0x lambda: template [=](){ putc(d); }

LISP closure: (repeat 10 (lambda (n) (putc d)))

Smalltalk: 10 timesRepeat:[pen turn:d; draw]

Ruby: z.each {|val| puts(val + d.to_s)}

C: repeat(10, ^{ putc(d); });

10

Repeat Block N Times Function

NSMutableString *str = [NSMutableString string];..repeat(12, ^{ [str appendFormat:@"rand: %d ", rand()];});

void repeat(int n, void (^blkPtr)(void)) { while (n-- > 0) { blkPtr(); }}

11

Arguments Body

^ BOOL (id str) { return [str length] > num; } ^ int (int val) { return rand() % val; }^ (int val) { return rand() % val; } Type inferred!

^ void (id item) { [item doSomeThings]; }^ (id item) { [item doSomeThings]; } Type inferred!

^ (void) { [local doSomeThing]; }^ { [local doSomeThing]; }

Type inferred!(void) avoided!

ReturnType

Block Literal Syntax Summary

12

About Blocks…

__block id keyForValue = nil;[dict enumerateKeysAndObjectsUsingBlock: ^ (id key, id value, BOOL *stop) { if ([object isEqual:sought)]) { keyForValue = key; *stop = YES; } }];

Introducing Blocks and Grand Central Dispatch on iPhone Russian HillWednesday 11:30AM

Advanced Objective-C and Garbage Collection Techniques Pacific HeightsFriday 11:30AM

• Start out on stack—fast!• Blocks are objects!• Can be copied to heap!

■ [^{...} copy]■ [block release]

• Used for■ Enumerations■ Callback notifications■ With GCD, moving work off the main thread■ With GCD, mutual exclusion, concurrency

13

Cocoa Touch Iteration Best Practice

for (id e in array) { ..e.. }

for (id k in dictionary) { ..k.. }

[array enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:^(id e, NSUInteger idx, BOOL *stop) { ..e..idx.. }];

[dict enumerateKeysAndObjectsUsingBlock: ^(id k, id obj, BOOL *stop) { ..k..obj.. }];

For enumerations that need more than one value at a time, use the collection Block APIs:

Fastest!

Safest!

Extensible!

14

Objective-C

Objective-C++

C

C++

15

Objective-C++

• Mix and match:■ Instance/Member variables■ Statements■ Declarations■ Exceptions■ Whole Classes

• CAN’T mix methods/functions• CAN’T subclass one from another

@class MyUIKitWidget;

class MyEngine { MyUIKitWidget *widget;};

@interface MyUIKitWidget : NSObject { MyEngine eng;}@end

@implementation MyUIKitWidget- (id)myUIKitWidgetMethod { MyEngine ff; throw [NSException new]; return nil;}

MyMixedClass.mm

16

ObjectsInheritance

17

Java, C++, C# Objective-C

member variable instance variable, ivar

member function method, instance method,-method, dash method

static method class method, "plus method",+method, plus method

static variable (global variable)

interface doing @protocol doing

class aclass @interface aclass

operator new +alloc

~destructor -dealloc

Terminology for Common ConceptsTable replaces code graphic.

Table look good?

18

DUCK-hash-parents-swim-fly

Classessingle-inheritanceof instance variables

@interface Duck : Bird <Swimmer, Flyer>

MACHINE-start

FLYER-fly

Protocols (Java: interface)

multiple-inheritanceof abstract methods

SWIMMER-swim

BIRD-hash-parents-fly

FISH-hash-parents-swim

AIRPLANE-hash-fly-start

ANIMAL-hash-parents

NSOBJECT-hash

19

@interface Animal (MythicalExtra)-(BOOL)isMythical;@end

Objective-C Category:

-hash-isEqual:-self

Bird

@implementation Animal (MythicalExtra)-(BOOL)isMythical { return NO; }@end

@implementation Dragon (MythicalExtra)-(BOOL)isMythical { return YES; }@end

Dragon

-hash-isEqual:-self-parents-fly

Your Application

-isMythical -isMythical -isMythical

-hash-isEqual:-self-parents

-hash-isEqual:-self-parents-fly

Apple Provided

NSObject Animal

20

Categories

• Add behavior to any class■ Use judiciously!

• Act like normal methods■ Can call [super ...]

• With a little code can add data■ Use Associative References

• Also can partition implementation■ Access to @private allowed■ Only within App/Framework!

@interface Animal (MythicalExtra)-(BOOL)isMythical;@end

@implementation Animal (MythicalExtra)-(BOOL)isMythical { return NO; }@end

21

Memory Management

22

Memory Management: The Basics

• Motivation: No crashes! No leaks!

• Cocoa Touch system originally designed for eight-megabyte systems!• Memory Management starts at the design phase

■ Object ownership is designed as Directed Acyclic Graph■ Ownership arises from simple pattern

■ Only +alloc, -initXXX, -retain, -copy, +newXXX create/transfer ownership.

• Apple LLVM Static Analyzer helps you follow simple rules• Apple Instrument Application measures memory behavior

23

1

1

2

1

1

1

1

1

1

1

1

2

1

2

1

1

1

1

0

0

1

0

0

0

0

0

0

0

0

0

0

0

0

Directed Acyclic Graph

0

24

Directed Acyclic Graph

1

1

1

1

25

21

Cyclic Graph

• "Up" (back) pointer creates loop• Objects never go away!

1

1

2

1

1

1

1

1

1

1

2

1

2

1

1

1

1

26

Simple Rules

• Instance variables are always either■ Retained■ Not retained

• Downlinks are retained• Uplinks are not retained

• Release old and■ Retain new values,

■ Unless from -initXXX or -copy

• Autorelease new results

1

1

2

1

1

1

1

1

1

1

1

2

1

2

1

1

1

1

27

How Autorelease Pools Work

d

e

Autorelease Pool

Stack

event pool

while (1) { NSEvent *event = getEvent(); id pool = [NSAutoreleasePool new]; process(event); [pool drain];}

@implementation NSDate...+ (id) date { return [[[self alloc] init] autorelease];}...@end

tmp

void process(NSEvent *event) { ... if ([event start] < [[NSDate date] ...])}

event

28

How Autorelease Pools Work

d

Stack

event pool

while (1) { NSEvent *event = getEvent(); id pool = [NSAutoreleasePool new]; process(event); [pool drain];}

void process(NSEvent *event) { ... if ([event start] < [[NSDate date] ...])}

event

e

Autorelease Pool

29

How Autorelease Pools Work

d

Stack

event pool

while (1) { NSEvent *event = getEvent(); id pool = [NSAutoreleasePool new]; process(event); [pool drain];}

e

Autorelease Pool

void process(NSEvent *event) { ... if ([event start] < [[NSDate date] ...])}

event

30

Accessors

31

Cocoa Getter/Setter Pattern

@interface CustomObject : NSObject { int balance;}- (int) balance;- (void) setBalance:(int)newBalance;@end

@implementation CustomObject- (int) balance { return balance; }- (void) setBalance:(int)newBalance { balance = newBalance;}@end

CustomObject.h:

CustomObject.m:

32

Properties: Automatic Declaration and MethodsWWDC2010: 32-bit simulator uses modern runtime!

@interface CustomObject : NSObject@property int balance;@end

@implementation CustomObject@synthesize balance;@end

@implementation CustomObject// @synthesize by default!!@end // Xcode 4 LLVM 2.0 Compiler!!

Advanced Objective-C and Garbage Collection Techniques Pacific HeightsFriday 11:30AM

CustomObject.h:

CustomObject.m:

33

Property AttributesAttributes define allowable behaviors

@interface CustomObject : NSObject@property(readonly) int balance;@end

@interface SuperCustom : CustomObject@property(readwrite) int balance;@end

34

All Attributes

getter=getBalance (and/or)setter=markBalance:

Custom method names

assign (or) retain (or) copy Object ownership policy

nonatomic Single-threaded only

readonly (or) readwrite Getter only (or) both, can be changed by subclass

35

Property ImplementationsYou can explicitly code any or all parts of an @property

@interface CustomObject : NSObject { int secretBalance;}@property int balance;@end

@implementation CustomObject- (int) balance { return secretBalance; }- (void) setBalance:(int)newBalance { secretBalance = newBalance;}@end

36

Property ImplementationsCan designate backing instance variable with @synthesize

@interface CustomObject : NSObject { int secretBalance;}@property int balance;@end

@implementation CustomObject@synthesize balance=secretBalance;@end

37

Deferred ImplementationMust use @dynamic

@interface CustomObject : NSObject@property int balance;@end

@implementation CustomObject@dynamic balance;@end

Advanced Objective-C and Garbage Collection Techniques Pacific HeightsFriday 11:30AM

38

@property(copy) Getter/Setter Pattern

- (NSString *) title { @synchronized(self) { return [[title retain] autorelease]; }}- (void) setTitle:(NSString *)newTitle { @synchronized(self) { NSString *tmp = [newTitle copy]; [title release]; title = tmp; }}

- (void) dealloc { [title release]; // or self.title = nil; [super dealloc];}

39

Cocoa Patterns

40

Selectors

• Selectors are data structures that represent a method “slot” name• The id object type allows any message to be sent without warning• Can ask respondsToSelector:

- (void) aMethod:(id)object { if ([object respondsToSelector:@selector(fred)])

[object fred];}

41

Delegation—Your Part

@interface MyDelegate <UIActionSheetDelegate>...@end

@implementation MyDelegate- (void)setUp { uiactionsheet.delegate = self;}- (void)willPresentActionSheet:(UIActionSheet *)as { ...}...

42

Delegation—UIKit Part

@protocol UIActionSheetDelegate <NSObject>@optional- (void)willPresentActionSheet:(UIActionSheet *)as; - (void)didPresentActionSheet:(UIActionSheet *)as;...@end

@interface UIActionSheet : UIView@property(nonatomic,assign) id<UIActionSheetDelegate> delegate;...@end

43

YOURS_NSU16Str _NSU8Str _NSCFStr

Class Clusters

• Behavior specified in abstract super classes• Private concrete implementations

NSString

44

NSString NSArray NSDictionary

“Property List” Abstract Value Classes

NSData NSNumber NSDate

NSObject

45

NSString NSArray NSDictionary

Abstract Mutable Value Class Pattern

NSData NSSet

NSObject

NSMutableString NSMutableArray NSMutableDictionary NSMutableData NSMutableSet

-copy-mutableCopy

-mutableCopy -copy

@protocol NSCopying- (id)copy;@end

@protocol NSMutableCopying- (id)mutableCopy;@end

46

Wrap-up

• Map and Go With What You Know■ Introduced Objective-C Terminology for Common Concepts

• Introduced Objective-C Uncommon Ideas■ Blocks■ @properties—let the compiler write your accessors!■ Categories—add behavior (methods!) to any class■ Selectors, Delegates, @optional

• Discussed Cocoa Touch Patterns■ Memory Management—Retain, Release, Autorelease■ Mutability, Class Clusters, “PLists”

Wrap-up?Summary?Reivew?

spelling of Wrap Up?

47

API Design for Cocoa and Cocoa Touch MarinaThursday 4:30PM

Related Sessions and Labs

Introducing Blocks and Grand Central Dispatch on iPhone Russian HillWednesday 11:30AM

Objective-C and Garbage Collection Lab Developer Tools Lab AThursday 2:00PM

Advanced Objective-C and Garbage Collection Techniques Pacific HeightsFriday 11:30AM

48

Michaelopolis JurewitzDeveloper Tools Evangelistjurewitz@apple.com

Apple Developer Forumshttp://devforums.apple.com

More Information

49

Q & A

50

51

52

53

top related