Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Natasha Murashev: Practical Protocol-Oriented P...
Search
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.8k
Self Branding with GitHub
realm
0
4.4k
Realm Mobile Platform overview and demo
realm
0
2.1k
Realm advanced topics and demo
realm
0
2.1k
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
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
320
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
160
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
200
速習iPhone Duo対応
yuukiw00w
2
780
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
480
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
150
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
3.6k
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
3.2k
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
250
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
160
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
340
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2.2k
Featured
See All Featured
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
The SEO identity crisis: Don't let AI make you average
varn
0
560
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Designing for Timeless Needs
cassininazir
1
510
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
500
A designer walks into a library…
pauljervisheath
211
25k
Everyday Curiosity
cassininazir
0
330
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
670
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
260
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
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