Protocol-Oriented Programming in Swift

Post on 14-Apr-2017

118 views 0 download

transcript

Protocol-Oriented Programming in Swift

Oleksandr Stepanov

We are hiring!

Agenda

Agenda

• Protocols in Swift vs Objective-C

Agenda

• Protocols in Swift vs Objective-C

• Protocol-oriented programming

‣ What is that? ‣ Why to use it? ‣ How to use it?

Agenda

• Protocols in Swift vs Objective-C

• Protocol-oriented programming

‣ What is that? ‣ Why to use it? ‣ How to use it?

• Examples

Protocols

protocol someProtocol {

}

protocol someProtocol { var someInt: Int { get } var someString: String? { get set }}

protocol someProtocol { var someInt: Int { get } var someString: String? { get set }

func doSomething(inputA: Int) -> String?}

protocol someProtocol { associatedtype TypeA;

var someInt: Int { get } var someString: String? { get set }

func doSomething(inputA: Int) -> String? func doSomethingWithTypeA(typeA: TypeA)}

protocol someProtocol { associatedtype TypeA;

var someInt: Int { get } var someString: String? { get set }

func doSomething(inputA: Int) -> String? func doSomethingWithTypeA(typeA: TypeA)}

protocol successorProtocol: someProtocol {

}

extension somethingProtocol { func doSomethingDifferent() { print("Oh man, that is different") } func doSomethingWithTypeA(typeA: TypeA) { print("typeA: \(typeA)") }}

ProtocolsSwift Objective-C

Protocol Inheritance ✅ ❌Protocol extensions ✅ ❌

Default implementation ✅ ❌Associated Types (aka Generics) ✅ ❌

Available in structures and enums as well ✅ ❌

Swift Objective-C

Protocol Inheritance ✅ ❌Protocol extensions ✅ ❌

Default implementation ✅ ❌Associated Types (aka Generics) ✅ ❌

Available in structures and enums as well ✅ ❌

Optional methods ❌ ✅

Protocols

import Foundation

@objc protocol optionalProtocol {

@objc optional func someOptionalMethod() @objc optional var someOptionalInt: Int { get set }

}

Swift Objective-C

Protocol Inheritance ✅ ❌Protocol extensions ✅ ❌

Default implementation ✅ ❌Associated Types (aka Generics) ✅ ❌

Available in structures and enums as well ✅ ❌

Optional methods ✅ (@objc) ✅

Protocols

Protocol-oriented programming

🤔

Protocol-oriented programming

What is this?

🤔

WWDC 2015 - Session 408

Protocol-Oriented Programming in Swift

“Swift is a protocol-oriented programming language.”

Dave Abrahams

WWDC 2015 - Session 408

Protocol-Oriented Programming in Swift

“Swift is a protocol-oriented programming language.”

Dave Abrahams

https://developer.apple.com/videos/play/wwdc2015/408/

https://developer.apple.com/videos/play/wwdc2016/419/

Cars project 🚗

Implementation Inheritance approach

class Car {let wheels = 4

func make() {print("🚗 is built")

} }

class Car {let wheels = 4

func make() {print("🚗 is built")

} } class CarFactory { var model: Car?

func makeACar() { model?.make() }}

…class Sedan: Car {}

let sedan = Sedan()

let carFactory = CarFactory()carFactory.model = sedancarFactory.makeACar() // prints “🚗 is built”

Let’s make 🏎

…class Bolide: Car {

override func make() { print("🏎 is built")

} }

let bolide = Bolide()let bolideFactory = CarFactory()bolideFactory.model = bolidebolideFactory.makeACar() // prints "🏎 is built" Page 1 of 1

Let’s make 🏍

Implementation Inheritance problems

class CarFactory { var model: Car?

func makeACar() { model?.make() }}

Tight coupling

Hard to maintain

Inheritance hierarchies

Hard to extend

class Car {let wheels = 4

func make() {print("🚗 is built")

} } class Sedan: Car {}

Implementation is a white-box

… even using proper encapsulation

class Car {let wheels = 4

func make() {print("🚗 is built")

} } class Sedan: Car {}

Protocol-oriented programming approach

✦ Separation of public interface from the implementation

✦ Separation of public interface from the implementation

✦ Software defined in components that talk to each other using interfaces

✦ Separation of public interface from the implementation

✦ Software defined in components that talk to each other using interfaces

✦ May be used in conjunction with classes, structs and enums.

protocol Vehicle {func make()

}

protocol WheelsVehicle { var wheels: Int { get }}

…protocol FourWheelsVehicle: WheelsVehicle {}

extension FourWheelsVehicle { var wheels: Int {

get { return 4

} }

}

…struct Car: Vehicle, FourWheelsVehicle { func make() {

print("🚗 is built") } }

}

struct Bolide: Vehicle, FourWheelsVehicle {func make() {

print("🏎 is built") }

}

…struct Car: Vehicle, FourWheelsVehicle { func make() {

print("🚗 is built") } }

}

struct Bolide: Vehicle, FourWheelsVehicle {func make() {

print("🏎 is built") }

}

…struct Car: Vehicle, FourWheelsVehicle { func make() {

print("🚗 is built") } }

}

struct Bolide: Vehicle, FourWheelsVehicle {func make() {

print("🏎 is built") }

}

…protocol TwoWheelsVehicle: WheelsVehicle {}

extension TwoWheelsVehicle { var wheels: Int { get { return 2 } } }

struct MotorBike: Vehicle, TwoWheelsVehicle { func make() {

print("🏍 is built") } }

}

…protocol VehicleFactory { var model: Vehicle? { get set }

func makeACar()}

extension VehicleFactory { func makeACar() { model?.make() }}

…extension VehicleFactory { func repairACar() {

// ... }

}

…class CarFactory: VehicleFactory { var model: Vehicle?}

let bolide = Bolide()let carFactory = CarFactory()

carFactory.model = bolidecarFactory.makeACar() // prints "🏎 is built"

✦ Reusability

✦ Reusability

✦ Extensibility

✦ Reusability

✦ Extensibility

✦ Black-boxed

✦ Reusability

✦ Extensibility

✦ Black-boxed

MORE MAINTAINABLE

Patterns where it can be useful

✦ Data types• Abstraction• Mock objects for test

✦ Data types• Abstraction• Mock objects for test

✦ Dependency injection

✦ Data types• Abstraction• Mock objects for test

✦ Dependency injection

✦ Detached architecture• MVVM

✦ Data types• Abstraction• Mock objects for test

✦ Dependency injection

✦ Detached architecture• MVVM

✦ Testing• Unit• A/B testing interfaces

Real life example

Real life exampleUIKit

Table view cell

import UIKit struct Event {}

class EventTableViewCell: UITableViewCell {}

import UIKit struct Event { let icon: UIImage? let title: String let date: Date}

class EventTableViewCell: UITableViewCell { @IBOutlet var iconView: UIImageView! @IBOutlet var titleLabel: UILabel! @IBOutlet var dateLabel: UILabel!}

import UIKit struct Event { let icon: UIImage? let title: String let date: Date}

class EventTableViewCell: UITableViewCell { @IBOutlet var iconView: UIImageView! @IBOutlet var titleLabel: UILabel! @IBOutlet var dateLabel: UILabel!

func set(event: Event) { iconView.image = event.icon titleLabel.text = event.title dateLabel.text = event.date.description

} }

Collection view cell

…class EventTableViewCell: UITableViewCell {

… func set(event: Event) { iconView.image = event.icon titleLabel.text = event.title dateLabel.text = event.date.description

} }

class EventCollectionViewCell: UICollectionViewCell {…

func set(event: Event) { iconView.image = event.icon titleLabel.text = event.title dateLabel.text = event.date.description

} }

Header view

…class EventTableViewCell: UITableViewCell { … func set(event: Event) { iconView.image = event.icon titleLabel.text = event.title dateLabel.text = event.date.description

} }class EventCollectionViewCell: UICollectionViewCell {

… func set(event: Event) { iconView.image = event.icon titleLabel.text = event.title dateLabel.text = event.date.description

} }class EventHeaderView: UIView {

… func set(event: Event) { iconView.image = event.icon titleLabel.text = event.title dateLabel.text = event.date.description} }

Maintenance

Maintenance

😢

POP approach

protocol EventViewProtocol { var iconView: UIImageView! { get set } var titleLabel: UILabel! { get set } var dateLabel: UILabel! { get set }

func set(event: Event)}

protocol EventViewProtocol { var iconView: UIImageView! { get set } var titleLabel: UILabel! { get set } var dateLabel: UILabel! { get set }

func set(event: Event)}

extension EventViewProtocol { func set(event: Event) {

iconView.image = event.icontitleLabel.text = event.titledateLabel.text = event.date.description

}}

…class EventTableViewCell: UITableViewCell { @IBOutlet var iconView: UIImageView! @IBOutlet var titleLabel: UILabel! @IBOutlet var dateLabel: UILabel!}

extension EventTableViewCell: EventViewProtocol{}

Test it!

🔨

…import XCTest

class TestView { var iconView: UIImageView! = UIImageView() var titleLabel: UILabel! = UILabel() var dateLabel: UILabel! = UILabel()}

extension TestView: EventViewProtocol {}

…let eventDate = Date.init()let event = Event.init(icon: UIImage.init(named: “testEventIcon”)

title: "event title", date: eventDate)

let testView = TestView()testView.set(event: event)

…let eventDate = Date.init()let event = Event.init(icon: UIImage.init(named: “testEventIcon”)

title: "event title", date: eventDate)

let testView = TestView()testView.set(event: event)

XCTAssertEqual ( testView.iconView.image, UIImage.init(named:”testEventIcon”) )

XCTAssertEqual ( testView.titleLabel.text, "event title” )

XCTAssertEqual ( testView.dateLabel.text, eventDate.description )

✦ No code duplication -> better maintainable

✦ No code duplication -> better maintainable

✦ Better testable

✦ No code duplication -> better maintainable

✦ Better testable

PROFIT!

One more sample POP + Enums

One more sample POP + Enums

NSNotification

- Literal string names

- Literal string names

- Potential for mismatched strings

- Literal string names

- Potential for mismatched strings

- There must be a better approach

- Slightly better …

- Slightly better …

- … but can we do even better?

}

}

}

How to enhance it with POP ?

}

✦ No mismatched strings

✦ No mismatched strings

✦Simpler to read and maintain

✦ No mismatched strings

✦Simpler to read and maintain

✦ Notification handlers may be classes, structs and enums

✦ No mismatched strings

✦Simpler to read and maintain

✦ Notification handlers may be classes, structs and enums

✦ … the same for notification type

reusability

reusability

extensibility

understandabilityreusability

extensibility

maintainability

understandabilityreusability

extensibility

maintainability

understandability

testability

reusability

extensibility

POP

maintainability

understandability

testability

reusability

extensibility

it’s not a

it’s not a

treat it carefully

Thank you!

Q&A