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

NSSpain 2016: Building Fabric.app in Swift

C0eafab7106ab63b8db4025e57c1a8d2?s=47 Javier Soto
September 16, 2016

NSSpain 2016: Building Fabric.app in Swift

Overview of some of the technical decisions made during the development of the Fabric app for iOS.

C0eafab7106ab63b8db4025e57c1a8d2?s=128

Javier Soto

September 16, 2016
Tweet

More Decks by Javier Soto

Other Decks in Programming

Transcript

  1. Building the Fabric iOS App @Javi 1 — "Building the

    Fabric iOS App" - @Javi. NSSpain 2016
  2. Outline → Fabric → GraphQL → Dependency Injection → Error

    Reporting → Fastlane 2 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  3. What's Fabric? 3 — "Building the Fabric iOS App" -

    @Javi. NSSpain 2016
  4. Fabric 4 — "Building the Fabric iOS App" - @Javi.

    NSSpain 2016
  5. Fabric 5 — "Building the Fabric iOS App" - @Javi.

    NSSpain 2016
  6. GraphQL1 1 http://graphql.org/ 6 — "Building the Fabric iOS App"

    - @Javi. NSSpain 2016
  7. GraphQL - Queries → GET /users/<user_id> 7 — "Building the

    Fabric iOS App" - @Javi. NSSpain 2016
  8. GraphQL - Queries → GET /users/<user_id> → GET /users/<user_id>/friends 8

    — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  9. GraphQL - Queries 9 — "Building the Fabric iOS App"

    - @Javi. NSSpain 2016
  10. GraphQL - Queries { user(id: 4802170) { name profilePicture(size: 50)

    { uri width } friends(first: 5) { id name } } } 10 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  11. GraphQL - Queries { "data": { "user": { "id": "4802170",

    "name": "Javi", "profilePicture": { "uri": "http://bit.ly/1E8lYDq", "width": 50 }, "friends": [ { "id": "305249", "name": "Jony Ive" }, { "id": "3108935", "name": "Elon Musk" } ] } } } 11 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  12. GraphQL - Features → Hierarchical, human-readable query language → Strongly-typed

    → Version free 12 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  13. GraphQL - GraphiQL 13 — "Building the Fabric iOS App"

    - @Javi. NSSpain 2016
  14. Dependency Injection 14 — "Building the Fabric iOS App" -

    @Javi. NSSpain 2016
  15. Dependency injection Software design pattern that implements inversion of control

    for resolving dependencies. An injection is the passing of a dependency to a dependent object that would use it. — https://en.wikipedia.org/wiki/ Dependency_injection 15 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  16. Dependencies → View Controller => Data Provider → Data Provider

    => API Client → Persistence Manager => Database Client 16 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  17. Dependency Resolution → Self-instantiation → Global access → Injection via

    setters → Injection via constructor 17 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  18. Dependency Resolution - Self-Instantiation class ViewController { private let dataProvider:

    DataProvider init() { self.dataProvider = DataProvider() } } 18 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  19. Dependency Resolution - Global Access class ViewController { private let

    dataProvider: DataProvider init() { self.dataProvider = DataProvider.shared } } 19 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  20. Dependency Resolution - Injection via Setters class ViewController { var

    dataProvider: DataProvider! init() { } } 20 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  21. Dependency Resolution - Injection via Constructor class ViewController { private

    let dataProvider: DataProvider init(dataProvider: DataProvider) { self.dataProvider = dataProvider } } 21 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  22. Easy vs Simple 22 — "Building the Fabric iOS App"

    - @Javi. NSSpain 2016
  23. Easy - Hard Simple - Complex 23 — "Building the

    Fabric iOS App" - @Javi. NSSpain 2016
  24. Dependency injection Implicit vs explicit 24 — "Building the Fabric

    iOS App" - @Javi. NSSpain 2016
  25. Dependency injection - UIStoryboard class UIStoryboard { func instantiateViewController(withIdentifier identifier:

    String) -> UIViewController } 25 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  26. Dependency injection - UIStoryboard let sb = UIStoryboard... let vc

    = sb.instantiateViewController(withIdentifier: "ID") as! ApplicationOverviewVC vc.userSession = ... vc.applicationID = ... 26 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  27. Dependency injection - UIStoryboard final class ApplicationOverviewVC { // I

    hope you like "!"s... var userSession: UserSession! var applicationID: String! func viewDidLoad() { super.viewDidLoad() self.userSession.foo() // Or... if let userSession = self.userSession { userSession.foo() } else { /* Can't do anything useful here... */ } } } 27 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  28. 28 — "Building the Fabric iOS App" - @Javi. NSSpain

    2016
  29. Dependency injection in the Fabric app final class ApplicationListViewController: UIViewController

    { init(viewModel: ApplicationListViewModel) } final class ApplicationListViewModel { init(fabricAPI: AuthenticatedFabricAPI) } public final class AuthenticatedFabricAPI { public init(session: Session) } public struct Session { let accessToken: String } 29 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  30. DataLoadState final class ApplicationListViewModel { var applications: [Application]? } 30

    — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  31. DataLoadState enum DataLoadState<T> { case loading case failed case loaded(T)

    } final class ApplicationListViewModel { var applications: DataLoadState<[Application]> = .loading } 31 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  32. Error Reporting 32 — "Building the Fabric iOS App" -

    @Javi. NSSpain 2016
  33. Error Reporting class Crashlytics { public func record(_ error: NSError,

    withAdditionalUserInfo: [AnyHashable : Any]?) } 33 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  34. Error Reporting 34 — "Building the Fabric iOS App" -

    @Javi. NSSpain 2016
  35. Error Reporting public protocol ReportableError: Swift.Error { var info: [String

    : Any] { get } var underlyingErrors: [ReportableError] { get } } 35 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  36. Error Reporting private enum URLHandlerError: ReportableError { case unknownURL(URL) case

    malformedURLMissingParameter /// This is useful because the `NSError` conversion will only give us a "code" integer. private var name: String { switch self { case .unknownURL: return "UnknownURL" case .malformedURLMissingParameter: return "MalformedURLMissingParameter" } } var info: [String : Any] { var info: [String : Any] = ["name": self.name] switch self { case let .unknownURL(url): info["url"] = url.path ?? "" case .malformedURLMissingParameter: () } return info } } 36 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  37. Error Reporting extension ReportableError { var errorCode: Int { return

    (self as Error).code } var errorDomain: String { return (self as Error).domain } var asNSError: NSError { return NSError( domain: self.errorDomain, code: self.errorCode, userInfo: self.info ) } } 37 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  38. Error Reporting var allErrors: [ReportableError] { return [ [self], self.underlyingErrors.flatMap

    { $0.allErrors } // Recur ] .flatMap { $0 } } 38 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  39. Error Reporting public final class ErrorReporting { // We get

    file and function names for free internal func report( error: ReportableError, filePath: StaticString = #file, functionName: StaticString = #function, lineNumber: Int = #line ) { error.allErrors.forEach { var userInfo = $0.info userInfo["file"] = "\((filePath as NSString).lastPathComponent):\(lineNumber)" userInfo["function"] = functionName Crashlytics.sharedInstance().recordError($0.asNSError, withAdditionalUserInfo: userInfo) } } } 39 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  40. 40 — "Building the Fabric iOS App" - @Javi. NSSpain

    2016
  41. Fastlane → Code signing → Deployment 41 — "Building the

    Fabric iOS App" - @Javi. NSSpain 2016
  42. Fastlane - Code Signing 42 — "Building the Fabric iOS

    App" - @Javi. NSSpain 2016
  43. Fastlane - Code Signing https://codesigning.guide/ 43 — "Building the Fabric

    iOS App" - @Javi. NSSpain 2016
  44. Fastlane - 44 — "Building the Fabric iOS App" -

    @Javi. NSSpain 2016
  45. Fastlane - Deployment 45 — "Building the Fabric iOS App"

    - @Javi. NSSpain 2016
  46. Fastlane - Deployment lane :appstore do snapshot # Generate screenshots

    for the App Store match # Ensure code signing is set-up gym # Build your app deliver # Upload the screenshots and the binary to iTunes slack # Let your team-mates know the new version is live end 46 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  47. Fastlane - Deployment lane :appstore do snapshot # Generate screenshots

    for the App Store match # Ensure code signing is set-up gym # Build your app deliver # Upload the screenshots and the binary to iTunes slack # Let your team-mates know the new version is live end $ fastlane appstore 47 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  48. Fastlane - Deployment lane :appstore do |options| ensure_git_branch(branch: "(master|release\\S+)") ensure_git_status_clean

    ensure_xcode_version(version: "8.0") increment_version_number(version_number: options[:version_number]) build_number = increment_build_number complete_version_number = "#{version_number} (#{build_number})" commit_version_bump(message: "Version bump to #{complete_version_number}") set_github_release(repository_name: "...", name: complete_version_number) ... end $ fastlane appstore version_number:1.6.0 48 — "Building the Fabric iOS App" - @Javi. NSSpain 2016
  49. Fastlane.tools 49 — "Building the Fabric iOS App" - @Javi.

    NSSpain 2016
  50. Questions? @Javi / javi@twitter.com 50 — "Building the Fabric iOS

    App" - @Javi. NSSpain 2016
  51. Thanks ! 51 — "Building the Fabric iOS App" -

    @Javi. NSSpain 2016