Slide 1

Slide 1 text

CBL in Swift Shota Nakagami

Slide 2

Slide 2 text

Talking about "CBL"

Slide 3

Slide 3 text

!

Slide 4

Slide 4 text

CBL Code-Based layout

Slide 5

Slide 5 text

I ! Code-Based Layout

Slide 6

Slide 6 text

How to layout ? 4 StoryBoard 4 XIB 4 Code-BasedʢProgrammaticallyʣ

Slide 7

Slide 7 text

Storyboard & XIB features 4 Ease of use ☺ 4 Segue ☺ 4 Visual (multi device screen size) 4 Constraint Checker ☺ 4 Non-Reusable " 4 Hard to Resolve Conflict " 4 Hard to review (XML) "

Slide 8

Slide 8 text

Testable? ! class ViewController: UIViewController { let dependency: Dependency // Dependency Injection with Initializer init(dependency: Dependency) { self.dependency = dependency } } 4 NG: Storyboard ☠ no initializer... 4 OK: XIB " 4 OK: CBL "

Slide 9

Slide 9 text

CBL features 4 Reusable ☺ 4 Speedy ☺ 4 Easy to Resolve Conflict ☺ 4 Easy to Review ☺ 4 Cost of Learning " 4 Non-Visual "

Slide 10

Slide 10 text

StoryBoard XIB Codebased ! Segue ✅ # Visual ✅ ✅ $ Compiler Check ✅ ✅ % Testable (DI) ✅ ✅ ♻ Reusable ✅ ' Less Conflict ✅ ( Reviewable ✅

Slide 11

Slide 11 text

6 Tips for CBL

Slide 12

Slide 12 text

1. Initialization Closure 2. "Then" 3. Custom View Class 4. lazy var 5. "SnapKit" 6. UIStackView

Slide 13

Slide 13 text

class ViewController: UIViewController { let priceLabel = UILabel() let imageView = UIImageView() override func viewDidLoad() { super.viewDidLoad() priceLabel.numberOfLines = 2 priceLabel.textColor = .red priceLabel.font = .boldSystemFont(ofSize: 14) imageView.contentMode = .scaleAspectFill imageView.clipsToBounds = true imageView.layer.cornerRadius = 4 // addSubview, AutoLayout... } }

Slide 14

Slide 14 text

messy viewDidLoad...

Slide 15

Slide 15 text

1. Initialization Closure

Slide 16

Slide 16 text

class ViewController: UIViewController { let priceLabel: UILabel = { let label = UILabel() label.numberOfLines = 2 label.textColor = .red label.font = .boldSystemFont(ofSize: 14) return label }() let imageView: UIImageView = { let view = UIImageView() view.contentMode = .scaleAspectFill view.clipsToBounds = true view.layer.cornerRadius = 4 return view }() override func viewDidLoad() { super.viewDidLoad() // addSubview, AutoLayout... } }

Slide 17

Slide 17 text

viewDidLoad is clean, but...

Slide 18

Slide 18 text

class ViewController: UIViewController { let priceLabel: UILabel = { // type annotation let label = UILabel() // renaming label.numberOfLines = 2 label.textColor = .red label.font = .boldSystemFont(ofSize: 14) return label // return }() let imageView: UIImageView = { // type annotation let view = UIImageView() // renaming view.contentMode = .scaleAspectFill view.clipsToBounds = true view.layer.cornerRadius = 4 return view // return }() override func viewDidLoad() { super.viewDidLoad() // addSubview, AutoLayout... } }

Slide 19

Slide 19 text

2. "Then" https://github.com/devxoul/Then

Slide 20

Slide 20 text

class ViewController: UIViewController { let priceLabel = UILabel().then { $0.numberOfLines = 2 $0.textColor = .red $0.font = .boldSystemFont(ofSize: 14) } let imageView = UIImageView().then { $0.contentMode = .scaleAspectFill $0.clipsToBounds = true $0.layer.cornerRadius = 4 } override func viewDidLoad() { super.viewDidLoad() // addSubview, AutoLayout... } }

Slide 21

Slide 21 text

3. Custom View Class

Slide 22

Slide 22 text

class ViewController: UIViewController { let priceLabel = PriceLabel() let imageView = ItemImageView() override func viewDidLoad() { super.viewDidLoad() } }

Slide 23

Slide 23 text

private let captureButton = CaptureButton().then { $0.onTapped = { [weak self] in self?.camera.capture() } }

Slide 24

Slide 24 text

private let captureButton = CaptureButton().then { $0.onTapped = { [weak self] in // Compile Error self?.camera.capture() // Compile Error } }

Slide 25

Slide 25 text

4. lazy var

Slide 26

Slide 26 text

private lazy var captureButton = CaptureButton().then { $0.onTapped = { [weak self] in self?.camera.capture() // OK } }

Slide 27

Slide 27 text

Codebased AutoLayout

Slide 28

Slide 28 text

NSLayoutAnchor ? // addSubview, AutoLayout... view.addSubview(button) button.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true button.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true button.topAnchor.constraintEqualToAnchor(view.topAnchor).active = true button.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor).active = true

Slide 29

Slide 29 text

!

Slide 30

Slide 30 text

5. "SnapKit" https://github.com/SnapKit/SnapKit

Slide 31

Slide 31 text

view.addSubview(button) // button.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true // button.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true // button.topAnchor.constraintEqualToAnchor(view.topAnchor).active = true // button.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor).active = true button.snp.makeConstraints { $0.edges.equalToSuperview() }

Slide 32

Slide 32 text

// readable button.snp.makeConstraints { $0.center.equalToSuperview() $0.size.equalTo(CGSize(width: 64, height: 64)) } // Support Safe Area tableView.snp.makeConstraints { $0.top.bottom.equalTo(view.safeAreaLayoutGuide) $0.leading.trailing.equalToSuperview() }

Slide 33

Slide 33 text

6. UIStackView

Slide 34

Slide 34 text

UIStackView = Stack "Layouted" View Less Constraints ! stackView.addArrangedSubview(label) stackView.addArrangedSubview(imageView) stackView.addArrangedSubview(button) label.snp.makeConstraints { $0.height.equalTo(20) } button.snp.makeConstraints { $0.height.equalTo(60) }

Slide 35

Slide 35 text

Summary

Slide 36

Slide 36 text

CBL: Code-Based layout 4 Testable, Speedy, and Reusable 4 Use "6 Tips" to clean code When to Use 4 Use CBL for simple layout 4 Use XIB for complicated layout 4 Use StoryBoard for segue