Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
iOS UI Component API Design
1. iOS UI Component Design
Configuration and Callbacks Using the
“Parameter Object”Pattern
Brian Gesiak
April 9th, 2014
Research Student, The University of Tokyo
@modocache
2. 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
10. But What About Categories?
Favoring Composition Over Inheritance
11. But What About Categories?
• JVFloatLabeledTextField is a subclass of UITextField
Favoring Composition Over Inheritance
12. But What About Categories?
• JVFloatLabeledTextField is a subclass of UITextField
• We need to use the class for its functionality
Favoring Composition Over Inheritance
13. 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
14. 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
15. 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
16. 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
49. options.onPan = ^(UIView *view,
MDCSwipeDirection direction,
CGFloat thresholdRatio){
if (direction == MDCSwipeDirectionLeft) {
NSLog(@"Panning to the left...");
}
};
Parameter Objects for Blocks
Extensible Block Signatures
50. options.onPan = ^(UIView *view,
MDCSwipeDirection direction,
CGFloat thresholdRatio){
if (direction == MDCSwipeDirectionLeft) {
NSLog(@"Panning to the left...");
}
};
Parameter Objects for Blocks
Extensible Block Signatures
51. options.onPan = ^(UIView *view,
MDCSwipeDirection direction,
CGFloat thresholdRatio){
if (direction == MDCSwipeDirectionLeft) {
NSLog(@"Panning to the left...");
}
};
Parameter Objects for Blocks
Extensible Block Signatures
52. options.onPan = ^(UIView *view,
MDCSwipeDirection direction,
CGFloat thresholdRatio){
if (direction == MDCSwipeDirectionLeft) {
NSLog(@"Panning to the left...");
}
};
Parameter Objects for Blocks
Extensible Block Signatures
53. options.onPan = ^(UIView *view,
MDCSwipeDirection direction,
CGFloat thresholdRatio){
if (direction == MDCSwipeDirectionLeft) {
NSLog(@"Panning to the left...");
}
};
Parameter Objects for Blocks
Extensible Block Signatures
options.onPan = ^(MDCPanState *state){
MDCSwipeDirection direction = state.direction;
54. options.onPan = ^(UIView *view,
MDCSwipeDirection direction,
CGFloat thresholdRatio){
if (direction == MDCSwipeDirectionLeft) {
NSLog(@"Panning to the left...");
}
};
Parameter Objects for Blocks
Extensible Block Signatures
options.onPan = ^(MDCPanState *state){
MDCSwipeDirection direction = state.direction;
55. Extensible Block Arguments
Update 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
56. Extensible Block Arguments
Update 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;
57. 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
58. 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
59. 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
60. 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
61. 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