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
Hatena Engineer Seminar #37「言語モデルの活用に関する研究」
slashnephy
0
520
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
1
2.6k
AIエージェントで 変わるAndroid開発環境
takahirom
2
660
音楽のための関数型プログラミング言語mimiumにおける多段階計算の活用
tomoyanonymous
1
330
AI がコードを書く時代における新卒エンジニアの仕事風景 (2026) / New Graduate Engineers in the Era of AI Coding (2026)
sushichan044
0
220
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
9.1k
コーディングルールの鮮度を保ちたい for SRE NEXT 2026 / keep-fresh-go-internal-conventions-sre-next-2026
handlename
0
140
Apache Hive: そしてCloud Native Lakehouseへ
okumin
1
130
【やさしく解説 設計編 #1】「ドメイン駆動」と「実装駆動」ってなに? 〜設計の考え方を、たとえ話で学ぼう〜
panda728
PRO
1
120
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
150
yield再入門 #phpcon
o0h
PRO
0
390
技術記事、 専門家としてのプログラマ、 言語化
mizchi
14
7.5k
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.9k
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
390
Optimizing for Happiness
mojombo
378
71k
Practical Orchestrator
shlominoach
191
11k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
350
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
610
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
220
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
460
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
450
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Thoughts on Productivity
jonyablonski
76
5.2k
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