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

Architecting iOS Apps for Fun & Profit

Oscar Swanros
September 23, 2015

Architecting iOS Apps for Fun & Profit

Presented at WDT September 2015.

How to architect an iOS app and have fun in the process.

Oscar Swanros

September 23, 2015
Tweet

More Decks by Oscar Swanros

Other Decks in Technology

Transcript

  1. Your needs depend on what you want to mean to

    your users. 1. ! Be fast 2. " Be reliable 3. # Be resilient 4. ✈ Be scalable 5. % Get the job done 6. & Extra! Oscar Swanros, 2015
  2. What I went with: • Swift 2.0 (!, ") •

    Frameworks! (✈) • Operation queue engine ($) • Leverage POP (✈) • Unit, UI tests (") • Beautiful UI (%) Oscar Swanros, 2015
  3. What I went with: • Swift 2.0 (!, ") •

    Frameworks! (✈) • Operation queue engine ($) • Leverage POP (✈) • Unit, UI tests (") • Beautiful UI (%) Oscar Swanros, 2015
  4. RBFoundation All the lower level stuff: • Extensions to Foundation

    & Swift types (Dictionary, NSLock, NSError, etc.) • Utils (curry, custom operators, data persistance) • Operation queue engine base implementation Oscar Swanros, 2015
  5. RBUIKit Anything that goes on or affects UI: • Dialogs

    • Network activity indicators • Custom colors • Custom fonts • Custom base UI elements Oscar Swanros, 2015
  6. RBNetworkKit Network stuff: • API Models • Data download •

    Data parsing • API Endpoint Manager • SSL pinning Oscar Swanros, 2015
  7. RBKit Reusable app tidbits: • Login screens • Image pickers

    • Specific buttons Oscar Swanros, 2015
  8. The graph • RBFoundation has no dependencies • RBUIKit depends

    on RBFoundation • RBNetworkKit depends on RBUIKit • RBKit depends on RBNetworkKit Oscar Swanros, 2015
  9. Operation • Represents an atomic unit of work • Fired

    once • Encapsulates state • Can be cancelled • NSOperation in Cocoa Oscar Swanros, 2015
  10. Operation queue • Operations run on an Operation queue •

    High-level thread • Can dispatch multiple operations at once • NSOperationQueue in Cocoa Oscar Swanros, 2015
  11. The operation queue handles 3 main things: • Operations •

    Conditions • Observers Oscar Swanros, 2015
  12. Operations may have conditions: stuff that needs to happen before

    the operation can be executed • Make sure we can access the internet • Make sure we can access the user's location • Make sure we can load the user's camera roll Oscar Swanros, 2015
  13. Operations may have observers: side effects • Show a network

    activity indicator whenever the app is making a network request • Update your cache after a successful download Oscar Swanros, 2015
  14. Operations may be comprised of other operations. • A GetJSONModelOperation

    needs to download and parse the JSON, but it is itself an operation • A group operation handles its own internal queue Oscar Swanros, 2015
  15. The model public final class Terminal: JSONParselable { dynamic public

    var id = 0 dynamic public var name = "name" // JSONParselable implementation public static func withData(data: [String:AnyObject]) -> Terminal? { let mkTerminal = curry { id, name in Terminal(id: id, name: name) } return toDict(data) >>>= { mkTerminal <*> int($0, "id") <*> string($0, "name") } } } Oscar Swanros, 2015
  16. Downloading Data - 1 let downloadTask = urlSession.downloadTaskWithRequest(request) { url,

    response, error in self.datarequestFinishedWithUrl(url, response: response, serror: error) } let networkTaskOperation = RBURLSessionTaskOperation(task: task) // Now our download task is an Operation Oscar Swanros, 2015
  17. Downloading Data - 2 let reachabilityCondition = ReachabilityCondition(host: endpointURL) networkTaskOperation.addCondition(reachabilityCondition)

    let networkObserver = NetworkActivityObserver() networkTaskOperation.addObserver(networkObserver) Oscar Swanros, 2015
  18. Finishing Downloading Data public class DownloadJSONOperation: RBGroupOperation { public init(cacheFile:

    NSURL) { // ... Previous 2 slides networkTaskOperation.addObserver(networkObserver) addOperation(networkTaskOperation) } } Oscar Swanros, 2015
  19. Parsing Data public class ParseJSONOperation<T: JSONParselable>: RBOperation { public init(cacheFile:

    NSURL) { self.cacheFile = c } override public func execute() { do { let json = try NSJSONSerialization.JSONObjectWithData(data) if let json = json { parse(json) } else { finish() } } catch let error as NSError { finishWithError(error) } } } Oscar Swanros, 2015
  20. Parsing Data - 1 private func parse(json: [String:AnyObject]) { self.parsedObjects

    = json.flatMap( T.withData($0) } process() finish() } Oscar Swanros, 2015
  21. Put it all together public class GetJSONModelOperation<T: JSONParselable>: RBGroupOperation {

    public init(query: [String:String], completion cf: Void -> Void) { super.init(operations: nil) let completion = NSBlockOperation(block: cf) parseOperation.addDependency(downloadOperation) completion.addDependency(parseOperation) addOperations([downloadOperation, parseOperation, completion]) } } Oscar Swanros, 2015
  22. Implement it public class GetTerminalsOperation: GetJSONModelOperation<Terminal> { override var downloadOperation:

    DownloadJSONOperation { return DownloadTerminalsOperation(query: query, cacheFile: cacheFile) } override var parseOperation: ParseJSONOperation<Terminal> { return ParseTerminalsOperation(cacheFile: cacheFile) } } Oscar Swanros, 2015
  23. Ship it class MyViewController: UIViewController { let operationQueue = RBOperationQueue()

    func search() { let op = GetTerminalsOperation(query: ["q":term]) { executeOnMainThread { [weak self] in self?.updateUI } } operationQueue.addOperation(q) } } Oscar Swanros, 2015
  24. Wrap! • Every app has its own needs • Think

    as the user • Architectural design goes hand in hand with UI design • Enjoy the process Oscar Swanros, 2015