Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Natasha Murashev: Practical Protocol-Oriented P...
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Realm
May 10, 2016
Programming
57k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Natasha Murashev: Practical Protocol-Oriented Programming
Realm
May 10, 2016
More Decks by Realm
See All by Realm
WWDC 2017 Review
realm
0
2.2k
Xcode shortcuts
realm
0
4.7k
Self Branding with GitHub
realm
0
4.3k
Realm Mobile Platform overview and demo
realm
0
2.1k
Realm advanced topics and demo
realm
0
2k
Realm introduction Seoul meetup 10
realm
0
2.2k
Stuart Hall: How I got 2.3 Million App Downloads
realm
0
2k
James Majors: What the Swiftly Func?
realm
1
4.3k
Simina Pasat: Continuous everything for iOS apps
realm
0
670
Other Decks in Programming
See All in Programming
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
9.1k
AI時代、エンジニアはどう育つのか -未経験エンジニアの成長を間近で見て考えたこと-
thasu0123
0
110
霧の中の代数的エフェクト
funnyycat
1
390
Performance Engineering for Everyone
elenatanasoiu
0
270
自作OSでスライド発表する
uyuki234
1
3.8k
OSINT for SRE: 学術論文とポストモーテムから探る システム障害の共通パターン / SRE NEXT 2026
tomoyk
1
3.7k
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
1.5k
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
150
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
230
これからAgentCoreを触る方へトレンドはGatewayです
har1101
6
490
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1.2k
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
180
Featured
See All Featured
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
220
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Are puppies a ranking factor?
jonoalderson
1
3.7k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
970
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
510
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
460
Claude Code のすすめ
schroneko
67
230k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Documentation Writing (for coders)
carmenintech
77
5.4k
What's in a price? How to price your products and services
michaelherold
247
13k
From π to Pie charts
rasagy
0
240
Transcript
@NatashaTheRobot
Protocol-Oriented Programming in Swift Dave Abrahams Professor of Blowing-Your-Mind
–- Professor of Blowing-Your-Mind "Swift Is a Protocol-Oriented Programming Language"
None
Practical POP • View • (UITable)ViewController • Networking
POP Views
None
None
// FoodImageView.swift import UIKit class FoodImageView: UIImageView { func shake()
{ let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.05 animation.repeatCount = 5 animation.autoreverses = true animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y)) animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y)) layer.addAnimation(animation, forKey: "position") } }
// ViewController.swift import UIKit class ViewController: UIViewController { @IBOutlet weak
var foodImageView: FoodImageView! @IBAction func onShakeButtonTap(sender: AnyObject) { foodImageView.shake() } }
None
None
// ShakeableButton.swift import UIKit class ActionButton: UIButton { func shake()
{ let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.05 animation.repeatCount = 5 animation.autoreverses = true animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y)) animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y)) layer.addAnimation(animation, forKey: "position") } }
// ViewController.swift class ViewController: UIViewController { @IBOutlet weak var foodImageView:
FoodImageView! @IBOutlet weak var actionButton: ActionButton! @IBAction func onShakeButtonTap(sender: AnyObject) { foodImageView.shake() actionButton.shake() } }
None
// UIViewExtension.swift import UIKit extension UIView { func shake() {
let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.05 animation.repeatCount = 5 animation.autoreverses = true animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 4.0, self.center.y)) animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 4.0, self.center.y)) layer.addAnimation(animation, forKey: "position") } }
class FoodImageView: UIImageView { // other customization here } class
ActionButton: UIButton { // other customization here } class ViewController: UIViewController { @IBOutlet weak var foodImageView: FoodImageView! @IBOutlet weak var actionButton: ActionButton! @IBAction func onShakeButtonTap(sender: AnyObject) { foodImageView.shake() actionButton.shake() } }
None
// Shakeable.swift import UIKit protocol Shakeable { } extension Shakeable
where Self: UIView { func shake() { // implementation code } }
class FoodImageView: UIImageView, Shakeable { } class ActionButton: UIButton, Shakeable
{ }
class FoodImageView: UIImageView, Shakeable, Dimmable { }
class FoodImageView: UIImageView, Dimmable { }
Transparent View Controllers and Dim Backgrounds totem.training
None
POP (UITable)ViewControllers
None
// FoodLaLaViewController override func viewDidLoad() { super.viewDidLoad() let foodCellNib =
UINib(nibName: "FoodTableViewCell", bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: "FoodTableViewCell") }
let foodCellNib = UINib(nibName: String(FoodTableViewCell), bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: String(FoodTableViewCell))
protocol ReusableView: class {} extension ReusableView where Self: UIView {
static var reuseIdentifier: String { return String(self) } }
extension UITableViewCell: ReusableView { } FoodTableViewCell.reuseIdentifier // FoodTableViewCell
let foodCellNib = UINib(nibName: "FoodTableViewCell", bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: FoodTableViewCell.reuseIdentifier)
protocol NibLoadableView: class { } extension NibLoadableView where Self: UIView
{ static var nibName: String { return String(self) } }
extension FoodTableViewCell: NibLoadableView { } FoodTableViewCell.nibName // "FoodTableViewCell"
let foodCellNib = UINib(nibName: FoodTableViewCell.nibName, bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: FoodTableViewCell.reuseIdentifier)
extension UITableView { func register<T: UITableViewCell where T: ReusableView, T:
NibLoadableView>(_: T.Type) { let nib = UINib(nibName: T.nibName, bundle: nil) registerNib(nib, forCellReuseIdentifier: T.reuseIdentifier) } }
let foodCellNib = UINib(nibName: "FoodTableViewCell", bundle: nil) tableView.registerNib(foodCellNib, forCellReuseIdentifier: "FoodTableViewCell")
tableView.register(FoodTableViewCell)
extension UITableView { func dequeueReusableCell<T: UITableViewCell where T: ReusableView>(forIndexPath indexPath:
NSIndexPath) -> T { guard let cell = dequeueReusableCellWithIdentifier(T.reuseIdentifier, forIndexPath: indexPath) as? T else { fatalError("Could not dequeue cell with identifier: \(T.reuseIdentifier)") } return cell } }
guard let cell = tableView.dequeueReusableCellWithIdentifier(“FoodTableViewCell", forIndexPath: indexPath) as? FoodTableViewCell else
{ fatalError("Could not dequeue cell with identifier: FoodTableViewCell") }
let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as FoodTableViewCell
if indexPath.row == 0 { return tableView.dequeueReusableCell(forIndexPath: indexPath) as DesertTableViewCell
} return tableView.dequeueReusableCell(forIndexPath: indexPath) as FoodTableViewCell
iOS Cell Registration & Reusing with Swift Protocol Extensions and
Generics medium.com/@gonzalezreal
Protocol-Oriented Segue Identifiers in Swift natashatherobot.com
None
POP Networking
struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { //
make asynchronous API call // and return appropriate result } }
enum Result<T> { case Success(T) case Failure(ErrorType) }
struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { //
make asynchronous API call // and return appropriate result } }
// FoodLaLaViewController var dataSource = [Food]() { didSet { tableView.reloadData()
} } override func viewDidLoad() { super.viewDidLoad() getFood() } private func getFood() { FoodService().getFood() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }
View Controller Tests?!!!
// FoodLaLaViewController var dataSource = [Food]() { didSet { tableView.reloadData()
} } override func viewDidLoad() { super.viewDidLoad() getFood() } private func getFood() { FoodService().getFood() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }
// FoodLaLaViewController func getFood(fromService service: FoodService) { service.getFood() { [weak
self] result in // handle result } }
// FoodLaLaViewControllerTests func testFetchFood() { viewController.getFood(fromService: FoodService()) // now what?
}
struct FoodService { func get(completionHandler: Result<[Food]> -> Void) { //
make asynchronous API call // and return appropriate result } }
protocol Gettable { associatedtype T func get(completionHandler: Result<T> -> Void)
}
struct FoodService: Gettable { func get(completionHandler: Result<[Food]> -> Void) {
// make asynchronous API call // and return appropriate result } }
// FoodLaLaViewController override func viewDidLoad() { super.viewDidLoad() getFood(fromService: FoodService()) }
func getFood<S: Gettable where S.T == [Food]>(fromService service: S) { service.get() { [weak self] result in switch result { case .Success(let food): self?.dataSource = food case .Failure(let error): self?.showError(error) } } }
// FoodLaLaViewControllerTests class Fake_FoodService: Gettable { var getWasCalled = false
func get(completionHandler: Result<[Food]> -> Void) { getWasCalled = true completionHandler(Result.Success(food)) } }
// FoodLaLaViewControllerTests func testFetchFood() { let fakeFoodService = Fake_FoodService() viewController.getFood(fromService:
fakeFoodService) XCTAssertTrue(fakeFoodService.getWasCalled) XCTAssertEqual(viewController.dataSource.count, food.count) XCTAssertEqual(viewController.dataSource, food) }
Update: View Controller Data Injection with Storyboards and Segues in
Swift natashatherobot.com
Protocols with Associated Types Alexis Gallagher 2015.funswiftconf.com
None
Practical POP • View • (UITable)ViewController • Networking
Beyond Crusty: Real-World Protocols Rob Napier thedotpost.com
Blending Cultures: The Best of Functional, Protocol-Oriented, and Object-Oriented Programming
Daniel Steinberg realm.io
@NatashaTheRobot