100
Ali Ozer Manager, Cocoa Frameworks 2

Ali Ozer - Huihoodocs.huihoo.com/apple/wwdc/2010/session_138__api_design_for_cocoa...Cocoa Tips and Tricks Marina Tuesday 2:00PM 56. Thread safety for a single property ... Cocoa text

Embed Size (px)

Citation preview

Ali OzerManager, Cocoa Frameworks

2

• Not■ Active Pharmaceutical Ingredient■ Armor-Piercing Incendiary■ American Pirate Industries■ American Pain Institute

• But■ Application Programming Interface

3

• APIs allow your code to interface with the system• Well-designed APIs:

■ Make you more productive ■ Allow you to leverage existing code■ Let you write code that works as the user expects

• APIs live for a long time• API design is UI design for developers

4

• Consistency• Performance• Safety• Reusability• Convenience

5

6

• Consistency■ Naming conventions

• Performance• Safety• Reusability• Convenience

7

Why is it important?

• Eliminates need to refer to documentation for every single API• Allows different subsystems to plug-in to each other more easily• Improves performance

8

Classes

• Use prefixes■ Protects against collisions■ Differentiate functional areas

NSStringUIViewCLLocation

9

Methods

• Focus on readability

• Use camel case• Choose clarity over brevity• Name all the arguments

- subviews- isEditable- insertObject:atIndex:

if (myTextField.isEditable) ...

10

• Use

• Rather than

• Or

- removeObjectAtIndex:

- removeObject:

- remove:

11

- (id)initWithBitmapDataPlanes:(unsigned char **)p pixelsWide:(NSInteger)width pixelsHigh:(NSInteger)height bitsPerSample:(NSInteger)bps samplesPerPixel:(NSInteger)spp hasAlpha:(BOOL)alpha isPlanar:(BOOL)isPlanar colorSpaceName:(NSString *)space bitmapFormat:(NSBitmapFormat)format bytesPerRow:(NSInteger)rBytes bitsPerPixel:(NSInteger)pBits;

12

- (id)initWithBitmapDataPlanes:(unsigned char **)p :(NSInteger)width :(NSInteger)height :(NSInteger)bps :(NSInteger)spp :(BOOL)alpha :(BOOL)isPlanar :(NSString *)space :(NSBitmapFormat)format :(NSInteger)rBytes :(NSInteger)pBits;

13

id image = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:planes pixelsWide:32 pixelsHigh:32 bitsPerSample:32 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:NSAlphaFirstBitmapFormat bytesPerRow:0 bitsPerPixel:0];

14

Java version, circa 2000

NSBitmapImageRep image = new NSBitmapImageRep( planes, 32, 32, 32, 4, true, false, NSDeviceRGBColorSpace, NSAlphaFirstBitmapFormat, 0, 0);

15

• For boolean properties that are adjectives, use “is” on the getter• Do not embellish the getter with “get” or other verbs

- color - setColor:- isEditable - setEditable: - drawsBackground - setDrawsBackground:

- (UIColor *)getColor;- (NSString *)computeFullName;- (CGImageRef)computeThumbnailImage;

16

Acceptable use of “get”

• Use “get” on accessors that return values by reference

• Callers pass NULL in for the arguments they don’t want

- (void)getLineDash:(CGFloat *)pattern count:(NSInteger *)count phase:(CGFloat *)phase;

- (void)getBytes:(void *)buffer range:(NSRange)range;

17

Using @property

@property (copy) UIColor *color;@property (getter=isEditable) BOOL editable;@property BOOL drawsBackground;

18

• Framework prefix, followed by the type or functionality area ■ “CF” + “Range” + “Make”■ “CG” + “Path” + “Add Lines”

• The common prefix allows easier searching and sorting

CFRangeMake()NSRectFill()CGPathAddLines()

19

• Similar to functions• We also use some common suffixes

■ …Notification■ …Key

UITouchPhaseBegan NSTextCheckingCityKey UIKeyboardWillHideNotification

20

Naming conventions have evolved over time

CFRangeMake()UIRectFrame()NSRectFill()

NSMakeRange()NSFrameRect()NSHeight()

21

• Good

• Bad

• Ugly

- setFloatingPointFormat:

- setFloatingPntFormat:

- setFltPntFmt:

22

Be consistent

• Acceptable abbreviations

• Commonly used acronyms are fine

alloc, allocWithZone:, deallocintmax, min

PDFUSBASCIIURLXML

23

• Use

• Rather than

remove

deletetakeOutdoAwayWitheliminateexterminateobliteratevaporize

24

- sendPort- displayName- center

- portForSending- localizedName- middle

25

“Block” can be ambiguous

• Use only in the generic cases

• Alternatives

- indexOfObjectsPassingTest:

- sortedArrayUsingComparator:

+ addLocalMonitorForEventsMatchingMask:handler:

- recycleURLs:completionHandler:

- beginBackgroundTaskWithExpirationHandler:

- enumerateObjectsUsingBlock:

26

Memory management

• Object ownership is not transferred across calls• Except return values from methods

■ Whose names begin with■ alloc■ new■ copy, mutableCopy

■ retain

• You should never have to ask the question “Do I have to release the result from calling … ?”

27

Marking memory management mistakes in APIs

• Use this for static analysis purposes, not to define or justify bad APIs

NS_RETURNS_RETAINED

- (NSString *)fullName NS_RETURNS_RETAINED;

28

29

• Consistency• Performance

■ Impedance matching■ Mutability■ Concurrency

• Safety• Reusability• Convenience

30

Why is it important?

• Users like it when applications are fast• Improves battery life

31

Small number of basic data types in APIs

• Improves consistency• Allows code to fit together more easily• Eliminates need to do conversions

32

Small number of basic data types in APIs

• NSString• NSDate• NSURL• NSArray, NSDictionary• UIColor/NSColor• UIFont/NSFont• UIImage/NSImage• …

33

Not all basic data types are objects

• Use C types for numeric values■ NSInteger, NSUInteger■ CGFloat■ NSNumber only to wrap these where necessary

• For widely used types where abstraction is not important, structs OK ■ CGPoint/NSPoint■ CFRange/NSRange■ …

34

Multiple types for the same concept

• What’s up with…■ CGPoint and NSPoint?

■ Equivalent typedefs■ NSInteger, NSUInteger?

■ Enable moving to 64-bit■ CFStringRef and NSString?

■ “Toll-free” bridged

35

Mutable means changeable

• Many objects are by nature only mutable■ NSWindow■ UIScrollView

• Others, usually “value” objects, can exist in immutable forms■ NSString■ UIColor

• In some cases both make sense

36

NSString versus NSMutableString

• NSString

• NSMutableString

NSString *str = ...;NSString *result = [str stringByAppendingString:@“!”];

NSMutableString *str = ...;[str appendString:@“!”];

37

Why have immutable variants at all?

• Performance• Simpler implementation• Thread safety• Easier analysis of program logic

38

Which one to use in APIs?

• Immutable

• Mutable

• Immutable version is almost always the right one to use• Using @property:

- (NSString *)title;

- (NSMutableString *)title;

@property (copy) NSString *title;

39

Very few exceptions

• NSAttributedString

• NSMutableAttributedString

- (NSString *)string;

- (NSMutableString *)mutableString;

40

Achieve higher performance on multi-core machines

• Blocks are a good fit for representing concurrent work■ They can be processed by GCD or NSOperationQueue■ They can capture state

• Not all block usage is necessarily concurrent

41

Often there is an explicit option for concurrency

• Enumeration, sorting, and searching in collections

- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;

[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger i, BOOL *stop) { // ... process obj ... }];

What’s New in Foundation for iOS 4 Pacific HeightsTuesday 10:15AM

42

Often there is an explicit option for concurrency

• Receiving NSNotifications

• Non-nil queue argument enables concurrent posting to observer

- (id)addObserverForName:(NSString *)name object:(id)object queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *))block;

43

Often there is an explicit option for concurrency

• Synchronous and asynchronous checking in NSSpellChecker

- (NSArray *)checkString:(NSString *)stringToCheck range:(NSRange)range types:(NSTextCheckingTypes)types options:(NSDictionary *)opts inSpellDocumentWithTag:(NSInteger)tag orthography:(NSOrthography **)orthography wordCount:(NSInteger *)wordCount;

- (NSInteger)requestCheckingOfString:(NSString *)stringToCheck range:(NSRange)range types:(NSTextCheckingTypes)types options:(NSDictionary *)opts inSpellDocumentWithTag:(NSInteger)tag completionHandler:(void (^)(NSInteger sequenceNumber, NSArray *results, NSOrthography *orthography, NSInteger wordCount))handler;

44

45

• Consistency• Performance• Safety

■ Runtime errors■ Programming errors■ Atomicity

• Reusability• Convenience

46

Why is it important?

• Reduces chance of crashes• Allows easier debugging• Makes more for robust and user-friendly applications

47

• Two major categories of errors:■ Runtime■ Programming

48

Errors that are expected to occur

• Unreadable file• Out of disk space• Lost network connection• Invalid user input• …

49

Handle with return values and optional NSError

• A basic return value (BOOL or an object value) to indicate success• In cases where reporting the error is interesting, an NSError

• NSError is often returned “by reference,” as last argument■ NULL may be passed in

- (id)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error;

50

Sometimes NSError is passed via other means

• Sent to delegate

• Passed to completion block

- (void)webView:(UIWebView *)view didFailLoadWithError:(NSError *)error;

- (void)duplicateURLs:(NSArray *)URLs completionHandler:(void (^)(NSDictionary *newURLs, NSError *error))handler;

51

Not all APIs need an NSError

• NSError returns best confined to APIs where:■ The caller may want to take conditional action based on type of error■ The error may be reported to the user

■ In AppKit, use NSResponder API:

- presentError:- presentError:modalForWindow:delegate:

52

Errors often caused by misuse of APIs

• Out-of-bounds access

• Invalid argument type

• Invalid parameter value

obj = [myArray objectAtIndex:[myArray count]];

[someView setBackgroundColor:@“0.4, 0.1, 0.1”];

[myTextField setStringValue:nil];

53

• Not indicated via return values

• But by exceptions■ NSException

- (ErrorCode)setBackgroundColor:(UIColor *)color;

54

Handling exceptions

• Typically exceptions are not meant to be caught

@try { [myView setBackgroundColor:someObject];} @catch (NSException *) { [myView setBackgroundColor:[UIColor blackColor]];}

55

Handling exceptions

• You may still consider registering a top level exception handler■ Alert the user that something bad happened■ Give them a chance to save their work and quit the app

Cocoa Tips and Tricks MarinaTuesday 2:00PM

56

Thread safety for a single property

• Objective-C 2.0 properties are by default “atomic”■ But they can be made non-atomic:

• Atomic guarantees that in the presence of multiple threads that get or set a property, the property is set or retrieved fully■ Provides a basic, low-level of thread safety for a single property■ But it does not provide consistency between properties

@property (nonatomic, copy) NSString *title;

57

Often a good idea to leave properties atomic

• When to consider non-atomic■ Performance critical usages

■ Look for objc_getProperty() or objc_setProperty() in samples■ Where you might already use a higher level of synchronization

■ Locks■ Queues■ Single-threaded access

Cocoa Performance Techniques WWDC 2008Session 412

58

59

• Consistency• Performance• Safety• Reusability

■ Subclassing■ Categories■ Patterns for communicating changes

• Convenience

60

Why is it important?

• No need to reinvent the wheel• You only write the code that distinguishes your application• Pieces of your application can be reused elsewhere

61

Subclassing

• Fundamental object-oriented programming feature• Not very commonly used in Cocoa and Cocoa Touch for customization

■ Many classes are “concrete” and usable as-is■ Some classes are meant for subclassing: “abstract” or “semi-abstract”

62

Some classes are meant for subclassing

• NSObject, UI/NSView, UI/NSViewController, UI/NSResponder, NSDocument

• Identify methods meant for overriding

- [NSObject init]- [UIView drawRect:]- [UIResponder canBecomeFirstResponder]- [NSDocument readFromURL:ofType:error:] ...

63

• Some Foundation value classes are abstract, but usable■ NSString, NSData, NSArray, NSDictionary, …

• alloc/init methods return proper instances• But subclasses don’t work unless some methods are overridden

■ “Primitives”

64

Primitive methods

• Minimal API to implement a new subclass

@interface NSString : NSObject

- (NSUInteger)length;- (unichar)characterAtIndex:(NSUInteger)index; @end

65

Why are these classes abstract?

• We do not want to encourage subclassing these classes to add additional properties■ Changes the fundamental meaning of what the object stores

- length- characterAtIndex:

- length- characterAtIndex:- font

66

Why are these classes abstract?

NSString *string = ...; // “Hello”

RichString *richString = ...; // “Hello”, Helvetica

[string isEqual:richString]

[richString isEqual:string]

Sure!

No way!

67

NSString versus NSAttributedString

- length- characterAtIndex:

- string- attributesAtIndex:

68

Why would you subclass NSString, NSData, NSArray, …?

• Implement the primitives to provide alternate storage■ Optimized for a given backing store■ Load elements lazily

Cocoa Fundamentals Guide: “Class Clusters” http://developer.apple.com

69

Categories

• Language feature• Allows adding methods on existing classes

■ All instances are affected

• Enables■ Declaring additional methods in other header files■ Extending a class without subclassing

70

Example

• Both UIKit and AppKit add new functionality to NSString

@interface NSString (UIStringDrawing)

- (CGSize)drawInRect:(CGPoint)loc withFont:(UIFont *)font;- (CGSize)drawAtPoint:(CGPoint)loc withFont:(UIFont *)font;...@end

71

- length- characterAtIndex:

- drawInRect:withFont:- drawAtPoint:withFont:

- length- characterAtIndex:- drawInRect:withFont:- drawAtPoint:withFont:

- length- characterAtIndex:

NSString and UIStringDrawing Category

NSString and DrawableString Subclass

72

Patterns for communicating changes

• Delegation• Notification• Key-value observing• Target-action

Cocoa Fundamentals Guide: “Cocoa Design Patterns” http://developer.apple.com

73

Delegation

• Allows an object to act on behalf of another• Not a language feature

■ Classes explicitly support delegates

@interface UITextView

@property(assign) id<UITextViewDelegate> delegate;

@end

74

Delegate methods declared as a protocol

@protocol UITextViewDelegate @optional- (BOOL)textViewShouldBeginEditing:(UITextView *)text;- (BOOL)textViewShouldEndEditing:(UITextView *)text;- (void)textViewDidChangeSelection:(UITextView *)text;...@end

75

• Allows one object to help many others

• Allows proper subdivision of responsibility• Flexible

delegate

delegate

delegate

dataSource

76

Notifications

• Allows happenings to be broadcast to a set of unrelated observers• Observers observe, but don’t interfere• Not a language feature

■ NSNotificationCenter provides the facility■ Classes declare the notifications they post

NSString *const UIPasteboardChangedNotification;NSString *const NSWindowWillCloseNotification;NSString *const UIKeyboardDidShowNotification;

77

• Allows multiple observers• Indirection between objects enables observing of

■ Any notification from a particular object■ A specific notification from any object

- postNotification:

78

Key-value observing

• Allows objects to broadcast updates to values of individual properties• Not a language feature

■ Classes decide which properties they want to implement this for■ Automatic for key-value coding compliant properties

79

Target-Action

• Allows UI controls to indicate user interaction• Simple approach, well-suited for use in Interface Builder

■ Controls send their target a custom action

• Use of responder chain makes target-action flexible

80

• Defines three clear functional roles for objects• Each piece separately replaceable/customizable• Used for overall app design, as well as at subsystem level:

■ Cocoa text system■ Cocoa bindings architecture■ UITableView, NSTableView■ Cocoa Touch UIViewController

Model-View-Controller for iPhone OS Russian HillWednesday 10:15AM

Advanced Cocoa Text Tips & Tricks Russian HillWednesday 9:00AM

81

82

• Consistency• Performance• Safety• Reusability• Convenience

■ Convenience APIs■ Blocks

83

There’s still time!

84

Why is it important?

• Allows you to be more productive• Makes coding fun

85

Convenience APIs

• APIs that simplify or combine a number of other calls into one

- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)opts range:(NSRange)compareRange locale:(id)locale;

- (NSComparisonResult)compare:(NSString *)string;

86

Convenience APIs

• We usually consider convenience APIs only in cases where■ The implementation is more than two lines,■ There is additional value, or■ There is valuable abstraction

87

Additional value

- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)opts range:(NSRange)compareRange locale:(id)locale;

- (NSComparisonResult)compare:(NSString *)string;

- (NSComparisonResult)compare:(NSString *)string { return [self compare:string options:0 range:NSMakeRange(0, [self length]) locale:nil];}

88

Additional value

• compare: allows easy use of sorting methods

• In fact we have more NSString comparison conveniences:

[myArray sortUsingSelector:@selector(compare:)];

- caseInsensitiveCompare:- localizedCompare:- localizedCaseInsensitiveCompare:- localizedStandardCompare:

89

Valuable abstraction

• This is currently documented to use:

• But the actual implementation will change over time

- localizedStandardCompare:

[string compare:otherStr options:NSCaseInsensitiveSearch |

NSNumericSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch range:NSMakeRange(0, [str length]) locale:[NSLocale currentLocale]];

90

Blocks

• Blocks do not enable anything that was impossible before• But they bring a lot of convenience

■ Ability to specify a piece of code inline■ Ability to capture state

91

Make compare variants less necessary

• Instead of

• Can now do

[myArray sortUsingComparator:^(id str1, id str2) { return [str1 compare:str2 options:NSNumericSearch]; }];

[myArray sortUsingFunction:myNumericSort context:NULL];

...

NSComparisonResult myNumericSort(id str1, id str2, void *ctxt) { return [str1 compare:str2 options:NSNumericSearch];}

92

New APIs for presenting sheets on NSSavePanel

• Leopard

• Snow Leopard

- (void)beginSheetForDirectory:(NSString *)path file:(NSString *)name modalForWindow:(NSWindow *)window modalDelegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;

- (void)beginSheetModalForWindow:(NSWindow *)window completionHandler:(void (^)(NSInteger result))blk;

93

New APIs for animations on UIView+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;

94

New APIs for animations on UIView

• iPhone OS 3

• iOS 4

[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:0.5];view.alpha = 0.0;[UIView commitAnimations];

[UIView animateWithDuration:0.5 animations:^{ view.alpha = 0.0; }];

Building Animation Driven Interfaces Pacific HeightsThursday 9:00AM

95

Almost there!

96

• Good API is a very important part of Cocoa and Cocoa Touch design• Modeling your APIs as Apple’s will allow your APIs to be

■ More predictable■ Widely reusable■ Better performing

• API Design is an evolving art

97

Bill DudneyFrameworks [email protected]

DocumentationCocoa Fundamentals GuideIntroduction to Coding Guidelines for CocoaAnd many more!http://developer.apple.com

Apple Developer Forumshttp://devforums.apple.com

98

99

100

101