Share
Embed
NSSpain 2016: Building Fabric.app in Swift
Overview of some of the technical decisions made during the development of the Fabric app for iOS.
Javier Soto
September 16, 2016
Transcript
51 slides
-
Building the Fabric iOS App @Javi 1 — "Building the
Fabric iOS App" - @Javi. NSSpain 2016 -
Outline → Fabric → GraphQL → Dependency Injection → Error
Reporting → Fastlane 2 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
What's Fabric? 3 — "Building the Fabric iOS App" -
@Javi. NSSpain 2016 -
Fabric 4 — "Building the Fabric iOS App" - @Javi.
NSSpain 2016 -
Fabric 5 — "Building the Fabric iOS App" - @Javi.
NSSpain 2016 -
GraphQL1 1 http://graphql.org/ 6 — "Building the Fabric iOS App"
- @Javi. NSSpain 2016 -
GraphQL - Queries → GET /users/<user_id> 7 — "Building the
Fabric iOS App" - @Javi. NSSpain 2016 -
GraphQL - Queries → GET /users/<user_id> → GET /users/<user_id>/friends 8
— "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
GraphQL - Queries 9 — "Building the Fabric iOS App"
- @Javi. NSSpain 2016 -
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 -
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 -
GraphQL - Features → Hierarchical, human-readable query language → Strongly-typed
→ Version free 12 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
GraphQL - GraphiQL 13 — "Building the Fabric iOS App"
- @Javi. NSSpain 2016 -
Dependency Injection 14 — "Building the Fabric iOS App" -
@Javi. NSSpain 2016 -
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 -
Dependencies → View Controller => Data Provider → Data Provider
=> API Client → Persistence Manager => Database Client 16 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
Dependency Resolution → Self-instantiation → Global access → Injection via
setters → Injection via constructor 17 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
Dependency Resolution - Self-Instantiation class ViewController { private let dataProvider:
DataProvider init() { self.dataProvider = DataProvider() } } 18 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
Dependency Resolution - Global Access class ViewController { private let
dataProvider: DataProvider init() { self.dataProvider = DataProvider.shared } } 19 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
Dependency Resolution - Injection via Setters class ViewController { var
dataProvider: DataProvider! init() { } } 20 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
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 -
Easy vs Simple 22 — "Building the Fabric iOS App"
- @Javi. NSSpain 2016 -
Easy - Hard Simple - Complex 23 — "Building the
Fabric iOS App" - @Javi. NSSpain 2016 -
Dependency injection Implicit vs explicit 24 — "Building the Fabric
iOS App" - @Javi. NSSpain 2016 -
Dependency injection - UIStoryboard class UIStoryboard { func instantiateViewController(withIdentifier identifier:
String) -> UIViewController } 25 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
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 -
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 -
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 -
DataLoadState final class ApplicationListViewModel { var applications: [Application]? } 30
— "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
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 -
Error Reporting 32 — "Building the Fabric iOS App" -
@Javi. NSSpain 2016 -
Error Reporting class Crashlytics { public func record(_ error: NSError,
withAdditionalUserInfo: [AnyHashable : Any]?) } 33 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
Error Reporting 34 — "Building the Fabric iOS App" -
@Javi. NSSpain 2016 -
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 -
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 -
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 -
Error Reporting var allErrors: [ReportableError] { return [ [self], self.underlyingErrors.flatMap
{ $0.allErrors } // Recur ] .flatMap { $0 } } 38 — "Building the Fabric iOS App" - @Javi. NSSpain 2016 -
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 -
Fastlane → Code signing → Deployment 41 — "Building the
Fabric iOS App" - @Javi. NSSpain 2016 -
Fastlane - Code Signing 42 — "Building the Fabric iOS
App" - @Javi. NSSpain 2016 -
Fastlane - Code Signing https://codesigning.guide/ 43 — "Building the Fabric
iOS App" - @Javi. NSSpain 2016 -
Fastlane - 44 — "Building the Fabric iOS App" -
@Javi. NSSpain 2016 -
Fastlane - Deployment 45 — "Building the Fabric iOS App"
- @Javi. NSSpain 2016 -
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 -
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 -
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 -
Questions? @Javi / [email protected] 50 — "Building the Fabric iOS
App" - @Javi. NSSpain 2016 -
Thanks ! 51 — "Building the Fabric iOS App" -
@Javi. NSSpain 2016