Objective-C & Swift: Interoperability Tips and Tricks

Objective-C & Swift: Interoperability Tips and Tricks

Talk given at Wizeline Academy in Mexico City.

3bb2abb35d54dfe7c3179cb2d7c049e7?s=128

Oscar Swanros

May 19, 2018
Tweet

Transcript

  1. None
  2. Oscar Swanros, iOS Engineering @ PSPDFKit @Swanros Objective-C / Swift

    Interoperability
  3. None
  4. None
  5. Large background image caption.

  6. None
  7. Agenda • Swift considerations • Objective-C considerations • Tips and

    tricks • Demo • Final thoughts
  8. ✋if Objective-C is your main language.

  9. ✋if Swift is your main language.

  10. What makes Swift special? Swift Considerations

  11. • Fun to write

  12. • Fun to write • Really expressive

  13. • Fun to write • Really expressive • Type safe!

  14. • Fun to write • Really expressive • Type safe!

    • No ABI stability just yet
  15. Why you don’t want to ditch it, just yet. Objective-C

    Considerations
  16. • You already know Objective-C

  17. • You already know Objective-C • ABI stability

  18. • You already know Objective-C • ABI stability • Flexibility

  19. • You already know Objective-C • ABI stability • Flexibility

    • Less work when trying to interact with low- level APIs.
  20. Why mix both?

  21. • Legacy project trying to incorporate new features?

  22. • Legacy project trying to incorporate new features? • New

    project using legacy dependencies?
  23. • Legacy project trying to incorporate new features? • New

    project using legacy dependencies? • Someone on your team doesn't know one of the two?
  24. Tips and tricks

  25. Weak references

  26. @protocol WZProcessorDelegate -(void)processorDidFinish:(WZProcessor *)processor; @end @interface WZProcessor @property (nonatomic, weak)

    id<WZProcessorDelegate> delegate; @end
  27. @protocol WZProcessorDelegate -(void)processorDidFinish:(WZProcessor *)processor; @end @interface WZProcessor @property (nonatomic, weak)

    id<WZProcessorDelegate> delegate; @end
  28. protocol WZProcessorDelegate { func processorDidFinish(processor: WZProcessor) } class WZProcessor {

    var delegate: WZProcessorDelegate? } ⚠
  29. protocol WZProcessorDelegate: class { func processorDidFinish(processor: WZProcessor) } class WZProcessor

    { weak var delegate: WZProcessorDelegate? }
  30. protocol WZProcessorDelegate: class { func processorDidFinish(processor: WZProcessor) } class WZProcessor

    { weak var delegate: WZProcessorDelegate? }
  31. @objc

  32. @objc • Expose Swift API to Objective-C • Make concrete

    Swift interfaces for Objective-C • Access the Objective-C runtime from Swift
  33. class WZManager { init(identifier: WZIdentifier) { // ... } func

    register(observer: WZObservable) { // ... } } Exposing API
  34. @objc class WZManager { @objc init(identifier: WZIdentifier) { // ...

    } @objc func register(observer: WZObservable) { // ... } } Exposing API All types involved need to be representable in Objective-C
  35. @interface WZBaseObject: NSObject <NSCoder> //... @end Concrete Interfaces class WZIterator:

    WZBaseObject { // ... }
  36. @interface WZBaseObject: NSObject <NSCoder> //... @end Concrete Interfaces @objc(WZIterator) class

    WZIterator: WZBaseObject { // ... }
  37. Access the Objective-C Runtime private extension Selector { static let

    didTapLoginButton = #selector(VC.didTapLoginButton) } class VC: UIViewController { @objc func didTapLoginButton() { } override func viewDidLoad() { super.viewDidLoad() button.addTarget(self, action: .didTapLoginButton, action: .to } }
  38. Enumerations

  39. enum cup_sizes { xs = 0, s m, l, xl

    };
  40. typedef NS_ENUM(NSUInteger, WZCupSize) { WZCupSizeExtraSmall = 0, WZCupSizeSmall, WZCupSizeMedium, WZCupSizeLarge,

    WZCupSizeExtraLarge };
  41. typedef NS_ENUM(NSUInteger, WZCupSize) { WZCupSizeExtraSmall = 0, WZCupSizeSmall, WZCupSizeMedium, WZCupSizeLarge,

    WZCupSizeExtraLarge };
  42. enum CupSize: Int { case extraSmall case small case medium

    case large case extraLarge }
  43. Extensible Enumerations

  44. typedef NS_ENUM(NSUInteger, WZShirtPattern) { WZShirtPatternFlowers = 0, WZShirtPatternPlaid, WZShirtPatternSquares, WZShirtPatternDots,

    WZShirtPatternLines };
  45. // Base definition typedef NSString *WZShirtPattern NS_TYPED_EXTENSIBLE_ENUM; // Specializations extern

    WZShirtPattern const WZShirtPatternFlowers; extern WZShirtPattern const WZShirtPatternPlaid; extern WZShirtPattern const WZShirtPatternSquares; extern WZShirtPattern const WZShirtPatternDots; extern WZShirtPattern const WZShirtPatternLines; struct ShirtPattern { typealias RawValue = String init(_ rawValue: RawValue) init(rawValue: rawValue) var rawValue: RawValue { get } static var flowers: ShirtPattern { get } static var plaid: ShirtPattern { get } static var squares: ShirtPattern { get } static var dots: ShirtPattern { get } static var lines: ShirtPattern { get } }
  46. // Base definition typedef NSString *WZShirtPattern NS_TYPED_EXTENSIBLE_ENUM; // Specializations extern

    WZShirtPattern const WZShirtPatternFlowers; extern WZShirtPattern const WZShirtPatternPlaid; extern WZShirtPattern const WZShirtPatternSquares; extern WZShirtPattern const WZShirtPatternDots; extern WZShirtPattern const WZShirtPatternLines; struct ShirtPattern { typealias RawValue = String init(_ rawValue: RawValue) init(rawValue: rawValue) var rawValue: RawValue { get } static var flowers: ShirtPattern { get } static var plaid: ShirtPattern { get } static var squares: ShirtPattern { get } static var dots: ShirtPattern { get } static var lines: ShirtPattern { get } }
  47. struct ShirtPattern { typealias RawValue = String init(_ rawValue: RawValue)

    init(rawValue: rawValue) var rawValue: RawValue { get } static var flowers: ShirtPattern { get } static var plaid: ShirtPattern { get } static var squares: ShirtPattern { get } static var dots: ShirtPattern { get } static var lines: ShirtPattern { get } } extension ShirtPattern { static var bubbles: ShirtPattern { // generate custom pattern } }
  48. Refining for Swift

  49. - (nullable Document)getDocumentWithId:(NSString *)id; func getDocument(with: String) -> Document?

  50. - (nullable Document)getDocumentWithId:(NSString *)id NS func getDocument(withId: String) -> Document?

  51. Demo!

  52. Don’t do it just because you can. Final thoughts…

  53. Don't use Swift if… • You're shipping a binary framework.

    • You need to interact with C++.
  54. Don't use Objective-C if… • You don't like Objective-C…

  55. If you need to mix the two… • Think about

    your use case • Use the tools a your disposal, see how open source projects manage this • Think seriously about starting with Objective-C, then adding Swift • Consider that Objective-C is more compatible with Swift than Swift is with Objective-C. • Organize your project neatly!
  56. oscar@swanros.com @swanros swanros.com Thanks! http://bit.ly/ioscdmx