Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swift User Group - April 2016: Building Fabric.app in Swift

Swift User Group - April 2016: Building Fabric.app in Swift

Collection to tidbits about the things I learned while building the Fabric app.

Javier Soto

April 14, 2016
Tweet

More Decks by Javier Soto

Other Decks in Programming

Transcript

  1. Outline 4 What is Fabric.app? 4 Tools used 4 Architecture

    4 Better with Swift 4 Error reporting "Building Fabric.app in Swift" - Javier Soto. April 2016 4
  2. Dependency management 4 SSL Pinning 4 Keychain 4 1Password integration

    4 Graphs 4 Networking, caching "Building Fabric.app in Swift" - Javier Soto. April 2016 10
  3. CocoaPods 4 More widely adopted 4 Less work to integrate

    frameworks 4 Easily link some frameworks only in Debug "Building Fabric.app in Swift" - Javier Soto. April 2016 12
  4. UIStoryboard final class ApplicationOverviewVC { // I hope you like

    "!"s... var userSession: UserSession! var applicationID: String! func viewDidLoad() { super.viewDidLoad() self.userSession.foo() } } "Building Fabric.app in Swift" - Javier Soto. April 2016 21
  5. Storyboards final class ApplicationOverviewVC { let userSession: UserSession let applicationID:

    String init(userSession: UserSession, applicationID: String) { self.userSession = userSession self.applicationID = applicationID super.init(nibName: ..., bundle: ...) } func viewDidLoad() { super.viewDidLoad() // Compile-time guarantee of object fully initialized self.userSession.foo() } } "Building Fabric.app in Swift" - Javier Soto. April 2016 22
  6. Architecture 4 Massive View Controllers 4 View Models 4 Glue-code

    View Controllers 4 Table View Data sources "Building Fabric.app in Swift" - Javier Soto. April 2016 31
  7. Architecture GenericTableViewDataSource protocol TableSectionType { associatedtype AssociatedTableRowType: TableRowType var rows:

    [AssociatedTableRowType] { get } var title: String? { get } } protocol TableRowType { } "Building Fabric.app in Swift" - Javier Soto. April 2016 33
  8. Architecture GenericTableViewDataSource final class GenericTableViewDataSource <Elements, SectionType: TableSectionType, RowType: TableRowType

    where SectionType.AssociatedTableRowType == RowType, SectionType: Equatable, RowType: Equatable>: NSObject, UITableViewDataSource "Building Fabric.app in Swift" - Javier Soto. April 2016 34
  9. Architecture GenericTableViewDataSource enum ProjectIssueRow: TableRowType, Equatable { case Loading case

    NoIssues case ErrorLoadingIssues case ProjectIssue(Issue) } return GenericTableViewDataSource( tableView: tableView, tableViewData: observableProperty, // Observable<Elements> computeSections: { elements in ... }, /// Pure function from `Elements` to `[SectionType]` configureRow: { row, indexPath in ... } /// Function from `RowType` to `UITableViewCell` ) "Building Fabric.app in Swift" - Javier Soto. April 2016 35
  10. Better with Swift 4 Nullability 4 Type-safe JSON parsing 4

    Code generation "Building Fabric.app in Swift" - Javier Soto. April 2016 37
  11. Nullability final class ApplicationListViewController: BaseFabricTableViewController { override viewDidLoad() { super.viewDidLoad()

    let session = UserSession.currentUserSession if let session = session session { session.requestApplications()... } // or... session!.requestApplications()... } "Building Fabric.app in Swift" - Javier Soto. April 2016 41
  12. Nullability final class ApplicationListViewController: BaseFabricTableViewController { init(viewModel: ApplicationListViewModel) } final

    class ApplicationListViewModel { init(fabricAPI: AuthenticatedFabricAPI) } public final class AuthenticatedFabricAPI { public init(authResponse: AuthResponse) } public final class AuthResponse { let accessToken: String } "Building Fabric.app in Swift" - Javier Soto. April 2016 42
  13. Nullability enum DataLoadState<T> { case Loading case Failed case Loaded(T)

    } final class ApplicationListViewModel { var applications: DataLoadState<[Application]> = .Loading } "Building Fabric.app in Swift" - Javier Soto. April 2016 45
  14. JSON Parsing Anti-Patterns public struct Application { public var ID:

    String? public var name: String? public var bundleIdentifier: String? public mutating func decode(j: [String: AnyObject]) { self.ID = j["id"] as? String self.name = j["name"] as? String self.bundleIdentifier = j["identifier"] as? String } } "Building Fabric.app in Swift" - Javier Soto. April 2016 47
  15. JSON Parsing Anti-Patterns public struct Application { public let ID:

    String public let name: String public let bundleIdentifier: String public static func decode(j: [String: AnyObject]) -> Application? { guard let ID = j["id"] as? String, let name = j["name"] as? String, let bundleIdentifier = j["identifier"] as? String else { return nil } return Application( ID: ID, name: name, bundleIdentifier: bundleIdentifier ) } } "Building Fabric.app in Swift" - Javier Soto. April 2016 48
  16. Type-safe JSON parsing import Decodable /// https://github.com/Anviking/Decodable public struct Application:

    Decodable { public let ID: String public let name: String public let bundleIdentifier: String public static func decode(j: AnyObject) throws -> Application { return try Application( ID: j => "id", name: j => "name", bundleIdentifier: j => "identifier" ) } } "Building Fabric.app in Swift" - Javier Soto. April 2016 49
  17. Code Generation /// Swift < 2.2 UIBarButtonItem(barButtonSystemItem: .Done, target: self,

    action: Selector("buttonTapped")) // Swift 2.2 UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: #selector(ViewController.buttonTapped)) "Building Fabric.app in Swift" - Javier Soto. April 2016 51
  18. Code Generation super.init(nibName: "ViewControllerNibName", bundle: nil) let nib = UINib(nibName:

    "NibName", bundle: nil) tableView.registerNib(nib, forCellReuseIdentifier: "ReuseIdentifier") let cell = tableView.dequeueReusableCellWithIdentifier("ReuseIdentifier", forIndexPath: indexPath) as! MyTableViewCell let image = UIImage(named: "ImageName")! "Building Fabric.app in Swift" - Javier Soto. April 2016 52
  19. Code Generation: R.swift https://github.com/mac-cain13/R.swift 4 Nibs 4 Reuse Identifiers 4

    Image names in asset catalogs 4 Other file names in the bundle "Building Fabric.app in Swift" - Javier Soto. April 2016 54
  20. Code Generation: R.swift https://github.com/mac-cain13/R.swift super.init(nibResource: R.nib.myViewController) class MyTableViewCell: UITableViewCell, ReusableNibTableViewCell

    { /// This will even fail to compile if it's not the right cell static let nibResource = R.nib.myTableViewCell } tableView.registerReusableNibCell(MyTableViewCell) let cell = MyTableViewCell.dequeueFromTableView(tableView, indexPath) let image = R.image.imageName "Building Fabric.app in Swift" - Javier Soto. April 2016 55
  21. Error Reporting do { try fileManager.createDirectoryAtPath(path, withIntermediateDirectories: true, attributes: nil)

    /// ... } catch { print("Error: \(error)") } "Building Fabric.app in Swift" - Javier Soto. April 2016 57
  22. Error Reporting do { try fileManager.createDirectoryAtPath(path, withIntermediateDirectories: true, attributes: nil)

    /// ... } catch { Crashlytics.sharedInstance().recordError(error, withAdditionalUserInfo: userInfo) } "Building Fabric.app in Swift" - Javier Soto. April 2016 58