Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UIKonf 2015: iOS API Design

UIKonf 2015: iOS API Design

A talk really isn't a talk without presenter notes and animations! For those, check out the Keynote file here: https://github.com/modocache/talks/blob/master/20150519-uikonf/ios-api-design.key

Brian Gesiak

May 19, 2015
Tweet

More Decks by Brian Gesiak

Other Decks in Technology

Transcript

  1. @interface BananaAlertView : UIAlertView + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString

    *)dismissButtonText; + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText tintColor:(UIColor *)tintColor; @end
  2. @interface BananaAlertView : UIAlertView + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString

    *)dismissButtonText; + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText tintColor:(UIColor *)tintColor; @end
  3. @implementation BananaAlertView + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText {

    [self showWithTitleText:titleText messageText:messageText dismissButtonText:dismissButtonText tintColor:[UIColor yellowColor]]; } + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText tintColor:(UIColor *)tintColor { // ... }
  4. @implementation BananaAlertView + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText {

    [self showWithTitleText:titleText messageText:messageText dismissButtonText:dismissButtonText tintColor:[UIColor yellowColor]]; } + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText tintColor:(UIColor *)tintColor { // ... }
  5. @implementation BananaAlertView + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText {

    [self showWithTitleText:titleText messageText:messageText dismissButtonText:dismissButtonText tintColor:[UIColor yellowColor]]; } + (void)showWithTitleText:(NSString *)titleText messageText:(NSString *)messageText dismissButtonText:(NSString *)dismissButtonText tintColor:(UIColor *)tintColor { // ... }
  6. public class BananaAlertView { public static func show( titleText: String,

    messageText: String, dismissButtonText: String) {
 // ... } }
  7. public class BananaAlertView { public static func show( titleText: String,

    messageText: String, dismissButtonText: String) {
 // ... } } dismissButtonText: String, tintColor: UIColor = UIColor.yellowColor()) { // ... }
  8. public typealias ButtonCallback = (buttonIndex: Int) -> () public class

    BananaAlertView { public static func show( titleText: String, messageText: String, dismissButtonText: String, dismissButtonCallback: ButtonCallback, tintColor: UIColor = UIColor.yellowColor()) { // ... } }
  9. public typealias ButtonCallback = (buttonIndex: Int) -> () public class

    BananaAlertView { public static func show( titleText: String, messageText: String, dismissButtonText: String, dismissButtonCallback: ButtonCallback, tintColor: UIColor = UIColor.yellowColor()) { // ... } }
  10. public typealias ButtonCallback = (buttonIndex: Int) -> () public class

    BananaAlertView { public static func show( titleText: String, messageText: String, dismissButtonText: String, dismissButtonCallback: ButtonCallback, tintColor: UIColor = UIColor.yellowColor()) { // ... } }
  11. public typealias ButtonCallback = (buttonIndex: Int) -> () public class

    BananaAlertView { public static func show( titleText: String, messageText: String, dismissButtonText: String, dismissButtonCallback: ButtonCallback, tintColor: UIColor = UIColor.yellowColor()) { // ... } }
  12. public typealias ButtonCallback = (buttonIndex: Int) -> () public class

    BananaAlertView { public static func show( titleText: String, messageText: String, dismissButtonText: String, dismissButtonCallback: ButtonCallback, tintColor: UIColor = UIColor.yellowColor()) { // ... } } (buttonIndex: Int, buttonTitle: String) -> ()
  13. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { (buttonIndex: Int) in
 // ...
 }, tintColor: UIColor.redColor() ) Cannot invoke 'show' with an argument list of type '(String, message… 
  14. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { (buttonIndex: Int) in
 // ...
 }, tintColor: UIColor.redColor() ) Cannot invoke 'show' with an argument list of type '(String, message… 
  15. public struct ButtonCallbackParameters { let buttonIndex: Int let buttonText: String

    } public typealias ButtonCallback = (buttonIndex: Int) -> ()
  16. public struct ButtonCallbackParameters { let buttonIndex: Int let buttonText: String

    } public typealias ButtonCallback = (buttonIndex: Int) -> ()
  17. public struct ButtonCallbackParameters { let buttonIndex: Int let buttonText: String

    } public typealias ButtonCallback = (buttonIndex: Int) -> () public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> ()
  18. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { (buttonIndex: Int) in
 // ...
 }, tintColor: UIColor.redColor() ) dismissButtonCallback: { parameters in if parameters.buttonText == "Rats." { // ... } },
  19. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { (buttonIndex: Int) in
 // ...
 }, tintColor: UIColor.redColor() ) dismissButtonCallback: { parameters in if parameters.buttonText == "Rats." { // ... } },
  20. public struct ButtonCallbackParameters { let buttonIndex: Int let buttonTitle: String

    } public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> ()
  21. public struct ButtonCallbackParameters { let buttonIndex: Int let buttonTitle: String

    } public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> () let totalButtonCount: Int
  22. public struct ButtonCallbackParameters { let buttonIndex: Int let buttonTitle: String

    } public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> () let totalButtonCount: Int
  23. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { parameters in if parameters.buttonText == "Rats." { // ... } }, tintColor: UIColor.redColor() )
  24. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { parameters in if parameters.buttonText == "Rats." { // ... } }, tintColor: UIColor.redColor() )
  25. public struct ButtonCallbackParameters { let buttonIndex: Int
 let buttonTitle: String


    let totalButtonCount: Int } public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> ()
  26. public struct ButtonCallbackParameters { let buttonIndex: Int
 let buttonTitle: String


    let totalButtonCount: Int } public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> () @availability(*, deprecated=2.0)
  27. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { parameters in if parameters.buttonText == "Rats." { // ... } }, tintColor: UIColor.redColor() )
  28. BananaAlertView.show( "500 Error", messageText: "Internal banana error.", dismissButtonText: "Rats.", dismissButtonCallback:

    { parameters in if parameters.buttonText == "Rats." { // ... } }, tintColor: UIColor.redColor() ) 'buttonText' was deprecated in * version 2.0 
  29. public struct AlertViewOptions {
 public let dismissButtonText: String
 public let

    tintColor: UIColor public let animationDuration: NSTimeInterval } public class BananaAlertView { public static func show( titleText: String, messageText: String, options: AlertViewOptions) { // ... } }
  30. public struct AlertViewOptions {
 public let dismissButtonText: String
 public let

    tintColor: UIColor public let animationDuration: NSTimeInterval } public class BananaAlertView { public static func show( titleText: String, messageText: String, options: AlertViewOptions) { // ... } } = AlertViewOptions()) { = "OK" = UIColor.yellowColor() = 1
  31. #

  32. @interface JVFloatLabeledTextField : UITextField @property (nonatomic, assign) CGFloat floatingLabelYPadding UI_APPEARANCE_SELECTOR;

    @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @end
  33. @interface JVFloatLabeledTextField : UITextField @property (nonatomic, assign) CGFloat floatingLabelYPadding UI_APPEARANCE_SELECTOR;

    @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @end
  34. CGRect frame = CGRectMake(0.f, 0.f, 100.f, 44.f); JVFloatLabeledTextField *textField =

    [[JVFloatLabeledTextField alloc] initWithFrame:frame]; textField.placeholder = @"Price"; textField.floatingLabelYPadding = 10.f; textField.floatingLabelTextColor = [UIColor blueColor];
  35. CGRect frame = CGRectMake(0.f, 0.f, 100.f, 44.f); JVFloatLabeledTextField *textField =

    [[JVFloatLabeledTextField alloc] initWithFrame:frame]; textField.placeholder = @"Price"; textField.floatingLabelYPadding = 10.f; textField.floatingLabelTextColor = [UIColor blueColor];
  36. @interface UITextField (JVFloatLabeledTextField) @property (nonatomic, assign) CGFloat floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property

    (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @end @interface JVFloatLabeledTextField : UITextField
  37. @interface UITextField (JVFloatLabeledTextField) @property (nonatomic, assign) CGFloat floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property

    (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @end
  38. @interface UITextField (JVFloatLabeledTextField) @property (nonatomic, assign) CGFloat floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property

    (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @end
  39. const void * const YPaddingKey = &YPaddingKey; - (void)setFloatingLabelYPadding:(CGFloat)yPadding {

    objc_setAssociatedObject( self, YPaddingKey, @(yPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC ); } - (CGFloat)floatingLabelYPadding { return [objc_getAssociatedObject(self, YPaddingKey) floatValue]; }
  40. const void * const YPaddingKey = &YPaddingKey; - (void)setFloatingLabelYPadding:(CGFloat)yPadding {

    objc_setAssociatedObject( self, YPaddingKey, @(yPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC ); } - (CGFloat)floatingLabelYPadding { return [objc_getAssociatedObject(self, YPaddingKey) floatValue]; }
  41. const void * const YPaddingKey = &YPaddingKey; - (void)setFloatingLabelYPadding:(CGFloat)yPadding {

    objc_setAssociatedObject( self, YPaddingKey, @(yPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC ); } - (CGFloat)floatingLabelYPadding { return [objc_getAssociatedObject(self, YPaddingKey) floatValue]; }
  42. @interface UITextField (JVFloatLabeledTextField) @property (nonatomic, assign) CGFloat floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property

    (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @end
  43. @interface UITextField (JVFloatLabeledTextField) @property (nonatomic, assign) CGFloat floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property

    (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @end
  44. const void * const YPaddingKey = &YPaddingKey; const void *

    const FontKey = &FontKey; const void * const TextColorKey = &TextColorKey; - (void)setFloatingLabelYPadding:(CGFloat)yPadding { objc_setAssociatedObject( self, YPaddingKey, @(yPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC ); } - (CGFloat)floatingLabelYPadding { return [objc_getAssociatedObject(self, YPaddingKey) floatValue];
  45. } - (UIFont *)floatingLabelFont { return objc_getAssociatedObject(self, FontKey); } -

    (void)setFloatingLabelTextColor:(UIColor *)color { objc_setAssociatedObject( self, TextColorKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC ); } - (UIColor *)floatingLabelTextColor { return objc_getAssociatedObject(self, TextColorKey); }
  46. extension UITextField { var floatingLabelYPadding: CGFloat { set { objc_setAssociatedObject(

    self, &YPaddingKey, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_ASSIGN) ) } get { if let padding = objc_getAssociatedObject( self, &YPaddingKey) as? CGFloat { return padding } else { return 0
  47. extension UITextField { var floatingLabelYPadding: CGFloat { set { objc_setAssociatedObject(

    self, &YPaddingKey, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_ASSIGN) ) } get { if let padding = objc_getAssociatedObject( self, &YPaddingKey) as? CGFloat { return padding } else { return 0
  48. &TextColorKey, newValue, objc_AssociationPolicy( OBJC_ASSOCIATION_RETAIN_NONATOMIC) ) } get { if let

    color = objc_getAssociatedObject( self, &TextColorKey) as? UIColor { return color } else { return UIColor.blackColor() } } } }
  49. // objc4-532/runtime/objc-references.mm
 
 // class AssociationsManager manages a lock /

    hash table // singleton pair. Allocating an instance acquires the // lock, and calling its assocations() method // lazily allocates it. class AssociationsManager { static OSSpinLock _lock; // associative references: // object pointer -> PtrPtrHashMap. static AssociationsHashMap *_map; public: AssociationsManager() { OSSpinLockLock(&_lock); } ~AssociationsManager() { OSSpinLockUnlock(&_lock); } };
  50. extension UITextField { var options: FloatLabelOptions { get { if

    let options = objc_getAssociatedObject( self, &OptionsKey) as? FloatLabelOptions { return options } else { return FloatLabelOptions() } } set { // ... } } }
  51. extension UITextField { var options: FloatLabelOptions { get { if

    let options = objc_getAssociatedObject( self, &OptionsKey) as? FloatLabelOptions { return options } else { return FloatLabelOptions() } } set { // ... } } }
  52. extension UITextField { var options: FloatLabelOptions { get { if

    let options = objc_getAssociatedObject( self, &OptionsKey) as? FloatLabelOptions { return options } else { return FloatLabelOptions() } } set { // ... } } }
  53. extension UITextField { var options: FloatLabelOptions { get { if

    let options = objc_getAssociatedObject( self, &OptionsKey) as? FloatLabelOptions { return options } else { return FloatLabelOptions() } } set { // ... } } }
  54. #

  55. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  56. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  57. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  58. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  59. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  60. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  61. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  62. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  63. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in switch state.direction { case .Left: self.bookmarkView.alpha = 0 self.dontBookmarkView.alpha = state.thresholdRatio case .Right: self.bookmarkView.alpha = state.thresholdRatio self.dontBookmarkView.alpha = 0 } } webView.mdc_swipeToChooseSetup(options)
  64. public struct ButtonCallbackParameters { let buttonIndex: Int
 let buttonTitle: String


    let totalButtonCount: Int } public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> ()
  65. public struct ButtonCallbackParameters { let buttonIndex: Int
 let buttonTitle: String


    let totalButtonCount: Int } public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> () @availability(*, deprecated=2.0)
  66. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in // ... } webView.mdc_swipeToChooseSetup(options)
  67. let options = MDCSwipeOptions() options.threshold = 130 options.onPan = {

    state in // ... } webView.mdc_swipeToChooseSetup(options)