61
iOS UI Component Design Conguration and Callbacks Using the “Parameter Object” Pattern Brian Gesiak April 9th, 2014 Research Student, The University of Tokyo @modocache

iOS UI Component API Design

Embed Size (px)

Citation preview

Page 1: iOS UI Component API Design

iOS UI Component DesignConfiguration and Callbacks Using the “Parameter Object” Pattern

Brian Gesiak

April 9th, 2014

Research Student, The University of Tokyo

@modocache

Page 2: iOS UI Component API Design

Today

• Problem: How do we allow users to customize UI elements?

• Appearance, animations, and behavior should be customizable

• Composition over inheritance • Solution: Configuration objects !

• Problem: How do we define an API for callbacks? • Public delegate and block callbacks are hard to deprecate or change

• Solution: Parameter objects

Page 3: iOS UI Component API Design

Customization API ExampleJVFloatLabeledTextField

Page 4: iOS UI Component API Design

Customization API ExampleJVFloatLabeledTextField

Page 5: iOS UI Component API Design

Customization API ExampleJVFloatLabeledTextField Appearance API

Page 6: iOS UI Component API Design

Customization API ExampleJVFloatLabeledTextField Appearance API

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

Page 7: iOS UI Component API Design

Customization API ExampleJVFloatLabeledTextField Appearance API

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

Page 8: iOS UI Component API Design

Customization API ExampleJVFloatLabeledTextField Appearance API

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

Page 9: iOS UI Component API Design

Customization API ExampleJVFloatLabeledTextField Appearance API

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

Page 10: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

Page 11: iOS UI Component API Design

But What About Categories?

• JVFloatLabeledTextField is a subclass of UITextField

Favoring Composition Over Inheritance

Page 12: iOS UI Component API Design

But What About Categories?

• JVFloatLabeledTextField is a subclass of UITextField• We need to use the class for its functionality

Favoring Composition Over Inheritance

Page 13: iOS UI Component API Design

But What About Categories?

• JVFloatLabeledTextField is a subclass of UITextField• We need to use the class for its functionality • We’re forced to choose it or other useful subclasses

Favoring Composition Over Inheritance

Page 14: iOS UI Component API Design

But What About Categories?

• JVFloatLabeledTextField is a subclass of UITextField• We need to use the class for its functionality • We’re forced to choose it or other useful subclasses• We need to subclass it to add functionality

Favoring Composition Over Inheritance

Page 15: iOS UI Component API Design

But What About Categories?

• JVFloatLabeledTextField is a subclass of UITextField• We need to use the class for its functionality • We’re forced to choose it or other useful subclasses• We need to subclass it to add functionality• It forces itself upon our inheritance hierarchy

Favoring Composition Over Inheritance

Page 16: iOS UI Component API Design

But What About Categories?

• JVFloatLabeledTextField is a subclass of UITextField• We need to use the class for its functionality • We’re forced to choose it or other useful subclasses• We need to subclass it to add functionality• It forces itself upon our inheritance hierarchy

Favoring Composition Over Inheritance

• If it were a category, we’d be able to use it with any UITextField

Page 17: iOS UI Component API Design

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

But What About Categories?Favoring Composition Over Inheritance

Page 18: iOS UI Component API Design

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

But What About Categories?Favoring Composition Over Inheritance

Page 19: iOS UI Component API Design

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

But What About Categories?Favoring Composition Over Inheritance

Page 20: iOS UI Component API Design

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

But What About Categories?Favoring Composition Over Inheritance

@interface UITextField (JVFloatLabeledTextField)

Page 21: iOS UI Component API Design

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

But What About Categories?Favoring Composition Over Inheritance

@interface UITextField (JVFloatLabeledTextField)

Page 22: iOS UI Component API Design

@interface JVFloatLabeledTextField : UITextField !@property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; !@end

But What About Categories?Favoring Composition Over Inheritance

objc_setAssociatedObject@interface UITextField (JVFloatLabeledTextField)

Page 23: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

Page 24: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

static void *JVFloatingLabelYPaddingKey = &JVFloatingLabelYPaddingKey; !- (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } !- (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } !/// Add custom setters and getters for all properties

Page 25: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

static void *JVFloatingLabelYPaddingKey = &JVFloatingLabelYPaddingKey; !- (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } !- (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } !/// Add custom setters and getters for all properties

Page 26: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

static void *JVFloatingLabelYPaddingKey = &JVFloatingLabelYPaddingKey; !- (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } !- (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } !/// Add custom setters and getters for all properties

Page 27: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

static void *JVFloatingLabelYPaddingKey = &JVFloatingLabelYPaddingKey; !- (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } !- (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } !/// Add custom setters and getters for all properties

Page 28: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

static void *JVFloatingLabelYPaddingKey = &JVFloatingLabelYPaddingKey; !- (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } !- (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } !/// Add custom setters and getters for all properties

Page 29: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

static void *JVFloatingLabelYPaddingKey = &JVFloatingLabelYPaddingKey; !- (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } !- (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } !/// Add custom setters and getters for all properties

Page 30: iOS UI Component API Design

But What About Categories?Favoring Composition Over Inheritance

static void *JVFloatingLabelYPaddingKey = &JVFloatingLabelYPaddingKey; !- (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } !- (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } !/// Add custom setters and getters for all properties

Doesn’t scale

Page 31: iOS UI Component API Design

Configuration ObjectsEncapsulate Configuration

Page 32: iOS UI Component API Design

Configuration ObjectsEncapsulate Configuration

Page 33: iOS UI Component API Design

Configuration ObjectsEncapsulate Configuration

Page 34: iOS UI Component API Design

Configuration ObjectsEncapsulate Configuration

Page 35: iOS UI Component API Design

Configuration ObjectsEncapsulate Configuration

Page 36: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

Page 37: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

Page 38: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 39: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 40: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 41: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 42: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 43: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 44: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 45: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 46: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 47: iOS UI Component API Design

Configuration Object ExampleMDCSwipeToChoose

MDCSwipeOptions *options = [MDCSwipeOptions new]; options.delegate = self; options.onPan = ^(MDCPanState *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ![self.webView mdc_swipeToChooseSetup:options];

Page 48: iOS UI Component API Design

Parameter Objects for BlocksExtensible Block Signatures

Page 49: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

Parameter Objects for BlocksExtensible Block Signatures

Page 50: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

Parameter Objects for BlocksExtensible Block Signatures

Page 51: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

Parameter Objects for BlocksExtensible Block Signatures

Page 52: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

Parameter Objects for BlocksExtensible Block Signatures

Page 53: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

Parameter Objects for BlocksExtensible Block Signatures

options.onPan = ^(MDCPanState *state){ MDCSwipeDirection direction = state.direction;

Page 54: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

Parameter Objects for BlocksExtensible Block Signatures

options.onPan = ^(MDCPanState *state){ MDCSwipeDirection direction = state.direction;

Page 55: iOS UI Component API Design

Extensible Block ArgumentsUpdate the API without Breaking Old Versions

@interface MDCPanState : NSObject !@property (nonatomic, strong) UIView *view; @property (nonatomic, assign) MDCSwipeDirection direction; @property (nonatomic, assign) CGFloat thresholdRatio; !@end

Page 56: iOS UI Component API Design

Extensible Block ArgumentsUpdate the API without Breaking Old Versions

@interface MDCPanState : NSObject !@property (nonatomic, strong) UIView *view; @property (nonatomic, assign) MDCSwipeDirection direction; @property (nonatomic, assign) CGFloat thresholdRatio; !@end

DEPRECATED_ATTRIBUTE;

Page 57: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

options.onPan = ^(MDCPanState *state){ MDCSwipeDirection direction = state.direction;

Extensible Block Arguments Slowly Phase Out Deprecated Parameters

Page 58: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

options.onPan = ^(MDCPanState *state){ MDCSwipeDirection direction = state.direction;

Extensible Block Arguments Slowly Phase Out Deprecated Parameters

Page 59: iOS UI Component API Design

options.onPan = ^(UIView *view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } };

options.onPan = ^(MDCPanState *state){ MDCSwipeDirection direction = state.direction;

Extensible Block Arguments Slowly Phase Out Deprecated Parameters

Page 60: iOS UI Component API Design

Takeaways

• Favor composition over inheritance when building UI components

• Build extensible, future-proof customization APIs using parameter objects

• Parameter objects are especially useful as block arguments

Page 61: iOS UI Component API Design

Additional Resources

• Follow me on Twitter and GitHub at @modocache • Today’s slides

• http://modocache.io/ios-ui-component-api-design • JVFloatLabeledTextField

• https://github.com/jverdi/JVFloatLabeledTextField • MDCSwipeToChoose

• https://github.com/modocache/MDCSwipeToChoose • The Parameter Object Design Pattern

• http://c2.com/cgi/wiki?ParameterObject