Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

DANCING WITH DINOSAURS OBJECTIVE-C & SWIFT INTEROP 2 — @basthomas, NSSpain, November 2021

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

▸ The Netherlands ▸ Germany ▸ The Netherlands (ish) ▸ Spain (ish) ▸ Ireland ▸ Rotterdam, the Netherlands 6 — @basthomas, NSSpain, November 2021

Slide 7

Slide 7 text

BAS ▸ XING Mobile Releases & Platform Team ▸ Apple macOS Accessibility ▸ WeTransfer 7 — @basthomas, NSSpain, November 2021

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

OBJECTIVE-C & SWIFT INTEROP 9 — @basthomas, NSSpain, November 2021

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

GENERATED INTERFACES 11 — @basthomas, NSSpain, November 2021

Slide 12

Slide 12 text

12 — @basthomas, NSSpain, November 2021

Slide 13

Slide 13 text

NULLABILITY 13 — @basthomas, NSSpain, November 2021

Slide 14

Slide 14 text

#import @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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

NS_ASSUME_NONNULL_BEGIN @interface BTBWatch : NSObject /// Interface here @end NS_ASSUME_NONNULL_END 16 — @basthomas, NSSpain, November 2021

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

@property (nonatomic, nullable) NSString *strapType; 18 — @basthomas, NSSpain, November 2021

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

- (NSInteger)currentHour; - (NSDate *)currentDate; @property (nonatomic, readonly) NSInteger currentHour; @property (nonatomic, readonly) NSDate *currentDate; 21 — @basthomas, NSSpain, November 2021

Slide 22

Slide 22 text

open func currentHour() -> Int open func currentDate() -> Date open var currentHour: Int { get } open var currentDate: Date { get } 22 — @basthomas, NSSpain, November 2021

Slide 23

Slide 23 text

open func setTimeWithHours(_ hours: Int, minutes: Int, seconds: Int) 23 — @basthomas, NSSpain, November 2021

Slide 24

Slide 24 text

- (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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

public let patekPhilippe: String public let aLangeSoehne: String public let omega: String public let meisterSinger: String 28 — @basthomas, NSSpain, November 2021

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

extension Watch.Brand { public static let mondaine: Watch.Brand } 31 — @basthomas, NSSpain, November 2021

Slide 32

Slide 32 text

typedef NS_OPTIONS(NSInteger, BTBComplication) { BTBComplicationDateWindow = 1 << 0, BTBComplicationPowerReserveIndicator = 1 << 1, BTBComplicationChronograph = 1 << 2 } NS_SWIFT_NAME(Watch.Complication); 32 — @basthomas, NSSpain, November 2021

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

LIGHTWEIGHT GENERICS 34 — @basthomas, NSSpain, November 2021

Slide 35

Slide 35 text

@property (nonatomic, readonly) NSArray *functions; open var functions: [Any] { get } 35 — @basthomas, NSSpain, November 2021

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

RECAP ▸ Generated Interfaces ▸ Nullability ▸ (Re)naming ▸ Enums and option sets ▸ Lightweight generics 37 — @basthomas, NSSpain, November 2021

Slide 38

Slide 38 text

II: EXPOSING SWIFT TYPES TO OBJECTIVE-C 38 — @basthomas, NSSpain, November 2021

Slide 39

Slide 39 text

POWERFUL ENUMS 39 — @basthomas, NSSpain, November 2021

Slide 40

Slide 40 text

enum Bookcase: String { case billy case hemnes case kallax } Bookcase.billy.rawValue // "billy" 40 — @basthomas, NSSpain, November 2021

Slide 41

Slide 41 text

// Bookcase.h // Nothing to be seeen here... 41 — @basthomas, NSSpain, November 2021

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

class Library { let bookcases: [Bookcase?] init(bookcases: [Bookcase?]) { self.bookcases = bookcases } } Library(bookcases: [.billy, nil, .kallax, .kallax]) 43 — @basthomas, NSSpain, November 2021

Slide 44

Slide 44 text

A SWIFT-FIRST APPROACH 44 — @basthomas, NSSpain, November 2021

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

RECAP ▸ Powerful enums ▸ Value type nullability ▸ Swift-first 46 — @basthomas, NSSpain, November 2021

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

#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

Slide 50

Slide 50 text

map, forEach, flatMap, reduce 50 — @basthomas, NSSpain, November 2021

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

- (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

Slide 54

Slide 54 text

@objc func perform(operation: String) async -> Int { ... } - (void)performWithOperation:(NSString * _Nonnull)operation completionHandler:(void (^ _Nullable)(NSInteger))completionHandler; 54 — @basthomas, NSSpain, November 2021

Slide 55

Slide 55 text

- (NSProgress *)takesALongTimeWithCompletionHandler: (void (^)(MyResult * _Nullable, NSError * _Nullable))completionHandler; 55 — @basthomas, NSSpain, November 2021

Slide 56

Slide 56 text

GENERICS 56 — @basthomas, NSSpain, November 2021

Slide 57

Slide 57 text

@interface Queue<__covariant ObjectType> : NSObject - (void)enqueue:(ObjectType)value; - (ObjectType)dequeue; @end 57 — @basthomas, NSSpain, November 2021

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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