Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Oscar Swanros, iOS Engineering @ PSPDFKit @Swanros Objective-C / Swift Interoperability

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Large background image caption.

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Agenda • Swift considerations • Objective-C considerations • Tips and tricks • Demo • Final thoughts

Slide 8

Slide 8 text

✋if Objective-C is your main language.

Slide 9

Slide 9 text

✋if Swift is your main language.

Slide 10

Slide 10 text

What makes Swift special? Swift Considerations

Slide 11

Slide 11 text

• Fun to write

Slide 12

Slide 12 text

• Fun to write • Really expressive

Slide 13

Slide 13 text

• Fun to write • Really expressive • Type safe!

Slide 14

Slide 14 text

• Fun to write • Really expressive • Type safe! • No ABI stability just yet

Slide 15

Slide 15 text

Why you don’t want to ditch it, just yet. Objective-C Considerations

Slide 16

Slide 16 text

• You already know Objective-C

Slide 17

Slide 17 text

• You already know Objective-C • ABI stability

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

• You already know Objective-C • ABI stability • Flexibility • Less work when trying to interact with low- level APIs.

Slide 20

Slide 20 text

Why mix both?

Slide 21

Slide 21 text

• Legacy project trying to incorporate new features?

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

• Legacy project trying to incorporate new features? • New project using legacy dependencies? • Someone on your team doesn't know one of the two?

Slide 24

Slide 24 text

Tips and tricks

Slide 25

Slide 25 text

Weak references

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

@objc

Slide 32

Slide 32 text

@objc • Expose Swift API to Objective-C • Make concrete Swift interfaces for Objective-C • Access the Objective-C runtime from Swift

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

@objc class WZManager { @objc init(identifier: WZIdentifier) { // ... } @objc func register(observer: WZObservable) { // ... } } Exposing API All types involved need to be representable in Objective-C

Slide 35

Slide 35 text

@interface WZBaseObject: NSObject //... @end Concrete Interfaces class WZIterator: WZBaseObject { // ... }

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Enumerations

Slide 39

Slide 39 text

enum cup_sizes { xs = 0, s m, l, xl };

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

enum CupSize: Int { case extraSmall case small case medium case large case extraLarge }

Slide 43

Slide 43 text

Extensible Enumerations

Slide 44

Slide 44 text

typedef NS_ENUM(NSUInteger, WZShirtPattern) { WZShirtPatternFlowers = 0, WZShirtPatternPlaid, WZShirtPatternSquares, WZShirtPatternDots, WZShirtPatternLines };

Slide 45

Slide 45 text

// 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 } }

Slide 46

Slide 46 text

// 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 } }

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Refining for Swift

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

Demo!

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

Don't use Swift if… • You're shipping a binary framework. • You need to interact with C++.

Slide 54

Slide 54 text

Don't use Objective-C if… • You don't like Objective-C…

Slide 55

Slide 55 text

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!

Slide 56

Slide 56 text

[email protected] @swanros swanros.com Thanks! http://bit.ly/ioscdmx