Save 37% off PRO during our Black Friday Sale! »

Dancing with Dinosaurs: Objective-C and Swift Interop

79fe3c13c618a61329298bdd6a86ec42?s=47 Bas Broek
November 18, 2021

Dancing with Dinosaurs: Objective-C and Swift Interop

In this presentation, we meet at an old friend (Objective-C) and how it interacts with its new friend (Swift).

From making our Objective-C code work great with Swift, to making our Swift code available in Objective-C as well; covering things from nullability and (advanced) renaming to option sets and generics.

… and the story behind me “meeting” the Swift programming language.

79fe3c13c618a61329298bdd6a86ec42?s=128

Bas Broek

November 18, 2021
Tweet

Transcript

  1. DANCING WITH DINOSAURS 1 — @basthomas, NSSpain, November 2021

  2. DANCING WITH DINOSAURS OBJECTIVE-C & SWIFT INTEROP 2 — @basthomas,

    NSSpain, November 2021
  3. JUNE 2, 2014 3 — @basthomas, NSSpain, November 2021

  4. OBJECTIVE-C 4 — @basthomas, NSSpain, November 2021

  5. ... WITHOUT THE C 5 — @basthomas, NSSpain, November 2021

  6. ▸ The Netherlands ▸ Germany ▸ The Netherlands (ish) ▸

    Spain (ish) ▸ Ireland ▸ Rotterdam, the Netherlands 6 — @basthomas, NSSpain, November 2021
  7. BAS ▸ XING Mobile Releases & Platform Team ▸ Apple

    macOS Accessibility ▸ WeTransfer 7 — @basthomas, NSSpain, November 2021
  8. BAS ▸ XING Mobile Releases & Platform Team Objective-C &

    Swift ▸ Apple macOS Accessibility Objective-C ▸ WeTransfer Swift 8 — @basthomas, NSSpain, November 2021
  9. OBJECTIVE-C & SWIFT INTEROP 9 — @basthomas, NSSpain, November 2021

  10. I: AUDITING OBJECTIVE-C FOR SWIFT 10 — @basthomas, NSSpain, November

    2021
  11. GENERATED INTERFACES 11 — @basthomas, NSSpain, November 2021

  12. 12 — @basthomas, NSSpain, November 2021

  13. NULLABILITY 13 — @basthomas, NSSpain, November 2021

  14. #import <Foundation/Foundation.h> @interface BTBWatch : NSObject - (NSInteger)currentHour; - (NSDate

    *)currentDate; - (BOOL)setTimeWithHours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)seconds error:(NSError **)error; - (void)printCurrentTime; @property (nonatomic) NSString *strapType; @property (nonatomic, readonly) NSArray *functions; @end 14 — @basthomas, NSSpain, November 2021
  15. open class BTBWatch : NSObject { open func currentHour() ->

    Int open func currentDate() -> Date! open func setTimeWithHours(_ hours: Int, minutes: Int, seconds: Int) throws open func printCurrentTime() open var strapType: String! open var functions: [Any]! { get } } 15 — @basthomas, NSSpain, November 2021
  16. NS_ASSUME_NONNULL_BEGIN @interface BTBWatch : NSObject /// Interface here @end NS_ASSUME_NONNULL_END

    16 — @basthomas, NSSpain, November 2021
  17. open class BTBWatch : NSObject { open func currentHour() ->

    Int open func currentDate() -> Date open func setTimeWithHours(_ hours: Int, minutes: Int, seconds: Int) throws open func printCurrentTime() open var strapType: String open var functions: [Any] { get } } 17 — @basthomas, NSSpain, November 2021
  18. @property (nonatomic, nullable) NSString *strapType; 18 — @basthomas, NSSpain, November

    2021
  19. open var strapType: String? 19 — @basthomas, NSSpain, November 2021

  20. (RE)NAMING 20 — @basthomas, NSSpain, November 2021

  21. - (NSInteger)currentHour; - (NSDate *)currentDate; @property (nonatomic, readonly) NSInteger currentHour;

    @property (nonatomic, readonly) NSDate *currentDate; 21 — @basthomas, NSSpain, November 2021
  22. open func currentHour() -> Int open func currentDate() -> Date

    open var currentHour: Int { get } open var currentDate: Date { get } 22 — @basthomas, NSSpain, November 2021
  23. open func setTimeWithHours(_ hours: Int, minutes: Int, seconds: Int) 23

    — @basthomas, NSSpain, November 2021
  24. - (void)setTimeWithHours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)seconds error:(NSError **)error NS_SWIFT_NAME(setTime(hours:minutes:seconds:)); 24 — @basthomas,

    NSSpain, November 2021
  25. open func setTime(hours: Int, minutes: Int, seconds: Int) throws 25

    — @basthomas, NSSpain, November 2021
  26. ENUMS AND OPTION SETS 26 — @basthomas, NSSpain, November 2021

  27. NS_ASSUME_NONNULL_BEGIN const NSString *patekPhilippe; const NSString *aLangeSoehne; const NSString *omega;

    const NSString *meisterSinger; NS_SWIFT_NAME(Watch) @interface BTBWatch : NSObject // ... 27 — @basthomas, NSSpain, November 2021
  28. public let patekPhilippe: String public let aLangeSoehne: String public let

    omega: String public let meisterSinger: String 28 — @basthomas, NSSpain, November 2021
  29. NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(Watch.Brand) typedef NSString * WatchBrand NS_TYPED_EXTENSIBLE_ENUM; const WatchBrand patekPhilippe;

    const WatchBrand aLangeSoehne; const WatchBrand omega; const WatchBrand meisterSinger; NS_SWIFT_NAME(Watch) @interface BTBWatch : NSObject // ... 29 — @basthomas, NSSpain, November 2021
  30. extension Watch { public struct Brand : Hashable, Equatable, RawRepresentable

    { public init(_ rawValue: String) public init(rawValue: String) } } extension Watch.Brand { public static let patekPhilippe: Watch.Brand public static let aLangeSoehne: Watch.Brand public static let omega: Watch.Brand public static let meisterSinger: Watch.Brand } 30 — @basthomas, NSSpain, November 2021
  31. extension Watch.Brand { public static let mondaine: Watch.Brand } 31

    — @basthomas, NSSpain, November 2021
  32. typedef NS_OPTIONS(NSInteger, BTBComplication) { BTBComplicationDateWindow = 1 << 0, BTBComplicationPowerReserveIndicator

    = 1 << 1, BTBComplicationChronograph = 1 << 2 } NS_SWIFT_NAME(Watch.Complication); 32 — @basthomas, NSSpain, November 2021
  33. extension Watch { public struct Complication : OptionSet { public

    init(rawValue: Int) public static var dateWindow: Watch.Complication { get } public static var powerReserveIndicator: Watch.Complication { get } public static var chronograph: Watch.Complication { get } } } 33 — @basthomas, NSSpain, November 2021
  34. LIGHTWEIGHT GENERICS 34 — @basthomas, NSSpain, November 2021

  35. @property (nonatomic, readonly) NSArray *functions; open var functions: [Any] {

    get } 35 — @basthomas, NSSpain, November 2021
  36. @property (nonatomic, readonly) NSArray<NSString *> *functions; open var functions: [String]

    { get } 36 — @basthomas, NSSpain, November 2021
  37. RECAP ▸ Generated Interfaces ▸ Nullability ▸ (Re)naming ▸ Enums

    and option sets ▸ Lightweight generics 37 — @basthomas, NSSpain, November 2021
  38. II: EXPOSING SWIFT TYPES TO OBJECTIVE-C 38 — @basthomas, NSSpain,

    November 2021
  39. POWERFUL ENUMS 39 — @basthomas, NSSpain, November 2021

  40. enum Bookcase: String { case billy case hemnes case kallax

    } Bookcase.billy.rawValue // "billy" 40 — @basthomas, NSSpain, November 2021
  41. // Bookcase.h // Nothing to be seeen here... 41 —

    @basthomas, NSSpain, November 2021
  42. VALUE TYPE NULLABILITY 42 — @basthomas, NSSpain, November 2021

  43. class Library { let bookcases: [Bookcase?] init(bookcases: [Bookcase?]) { self.bookcases

    = bookcases } } Library(bookcases: [.billy, nil, .kallax, .kallax]) 43 — @basthomas, NSSpain, November 2021
  44. A SWIFT-FIRST APPROACH 44 — @basthomas, NSSpain, November 2021

  45. DON'T LIMIT YOURSELF 45 — @basthomas, NSSpain, November 2021

  46. RECAP ▸ Powerful enums ▸ Value type nullability ▸ Swift-first

    46 — @basthomas, NSSpain, November 2021
  47. III: ADVANCED INTEROPABILITY 47 — @basthomas, NSSpain, November 2021

  48. SWIFTIER OBJECTIVE-C 48 — @basthomas, NSSpain, November 2021

  49. #if defined(__cplusplus) #define let auto const #else #define let const

    __auto_type #endif #if defined(__cplusplus) #define var auto #else #define var __auto_type #endif 49 — @basthomas, NSSpain, November 2021
  50. map, forEach, flatMap, reduce 50 — @basthomas, NSSpain, November 2021

  51. ASYNC-AWAIT 51 — @basthomas, NSSpain, November 2021

  52. "IT JUST WORKS" SE-0297 52 — @basthomas, NSSpain, November 2021

  53. - (void)fetchShareParticipantWithUserRecordID:(CKRecordID *)userRecordID completionHandler:(void (^)(CKShareParticipant * _Nullable, NSError * _Nullable))completionHandler;

    func fetchShareParticipant( withUserRecordID userRecordID: CKRecord.ID, completionHandler: @escaping (CKShare.Participant?, Error?) -> Void ) func fetchShareParticipant( withUserRecordID userRecordID: CKRecord.ID ) async throws -> CKShare.Participant 53 — @basthomas, NSSpain, November 2021
  54. @objc func perform(operation: String) async -> Int { ... }

    - (void)performWithOperation:(NSString * _Nonnull)operation completionHandler:(void (^ _Nullable)(NSInteger))completionHandler; 54 — @basthomas, NSSpain, November 2021
  55. - (NSProgress *)takesALongTimeWithCompletionHandler: (void (^)(MyResult * _Nullable, NSError * _Nullable))completionHandler;

    55 — @basthomas, NSSpain, November 2021
  56. GENERICS 56 — @basthomas, NSSpain, November 2021

  57. @interface Queue<__covariant ObjectType> : NSObject - (void)enqueue:(ObjectType)value; - (ObjectType)dequeue; @end

    57 — @basthomas, NSSpain, November 2021
  58. RECAP ▸ Swiftier Objective-C ▸ Async-await ▸ Generics 58 —

    @basthomas, NSSpain, November 2021
  59. ¡GRACIAS! @BASTHOMAS 59 — @basthomas, NSSpain, November 2021

  60. REFERENCES ▸ https://developer.apple.com/videos/play/wwdc2020/10680/ ▸ https://basbroek.nl/objc-swift-interop-auditing ▸ https://basbroek.nl/there-and-back-again ▸ https://pspdfkit.com/blog/2017/even-swiftier-objective-c/ ▸

    https://github.com/apple/swift-evolution/blob/main/proposals/ 60 — @basthomas, NSSpain, November 2021