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

Balance

 Balance

Balancing the new awesome with Swift, and the old ways with Objective C is not always easy. I went over some of the things I've learned over the years putting the two worlds together.

Saul Mora

March 30, 2017
Tweet

More Decks by Saul Mora

Other Decks in Technology

Transcript

  1. nil

  2. let fileManager = NSFileManager() if let filePath = fileURL.path {

    if fileManager.fileExistsAtPath(filePath) { var error: NSError? let fileAttributes = fileManager.attributesOfItemAtPath(filePath, error: &error) if let fileAttributes = fileAttributes { if let creationDate = fileAttributes[NSFileModificationDate] as? NSDate { return creationDate .isBefore(NSDate.oneDayAgo()) } } else { NSLog("No file attributes \(filePath)") } } }
  3. extension Bundle { var bundleVersion: String { let bundleVersionKey =

    kCFBundleVersionKey as String let bundleShortVersionkey = "CFBundleShortVersionString" let version = (infoDictionary >>- { $0[bundleVersionKey] }) ?? (infoDictionary >>- { $0[bundleShortVersionkey] }) return version as? String ?? "0.0.0" } }
  4. extension Bundle { var bundleVersion: String { let bundleVersionKey =

    kCFBundleVersionKey as String let bundleShortVersionkey = "CFBundleShortVersionString" let version = (infoDictionary >>- { $0[bundleVersionKey] }) ?? (infoDictionary >>- { $0[bundleShortVersionkey] }) return version as? String ?? "0.0.0" } } import Runes
  5. extension Bundle { var bundleVersion: String { let bundleVersionKey =

    kCFBundleVersionKey as String let bundleShortVersionkey = "CFBundleShortVersionString" let version = (infoDictionary >>- { $0[bundleVersionKey] }) ?? (infoDictionary >>- { $0[bundleShortVersionkey] }) return version as? String ?? "0.0.0" } } import Runes
  6. extension Bundle { private var bundleInfo: [String: Any] { return

    infoDictionary ?? [:] } var bundleVersion: String { let bundleVersionKey = kCFBundleVersionKey as String let bundleShortVersionkey = "CFBundleShortVersionString" let version = (infoDictionary >>- { $0[bundleVersionKey] }) ?? (infoDictionary >>- { $0[bundleShortVersionkey] }) return version as? String ?? "0.0.0" } } import Runes
  7. extension Bundle { private var bundleInfo: [String: Any] { return

    infoDictionary ?? [:] } var bundleVersion: String { let bundleVersionKey = kCFBundleVersionKey as String let bundleShortVersionkey = "CFBundleShortVersionString" let version = bundleInfo[bundleVersionKey] ?? bundleInfo[bundleShortVersionkey] return version as? String ?? "0.0.0" } }
  8. !

  9. ! • Remove a framework • Code is using standard

    operators • Less complex syntax
  10. "

  11. let result: Result<T, Error> = … result.map { // use

    value ($0) in here } .mapError { error and in // handle error here }
  12. func doSomethingAsync() throws -> Double { do { DispatchQueue.background.async {

    throw MyErrors.hadNothingToDo } } catch { ///... } }
  13. let promise = doSomething() promise.then { // use promised value

    ($0) in here } .catch { error and in // handle error here }
  14. func doSomething() -> Promise<Double> { return Promise { fulfill, reject

    in /// if success { fulfill(10.0) } else { reject(MyError.unableToCompute) } }
  15. !

  16. App

  17. class ModuleHost { let loginModule = LoginModule() let main =

    MainModule() let profile = ProfileModule() var messageBus: AnyObject { return main.coordinator } func setup() { main.coordinator.next = loginModule.coordinator loginModule.coordinator.next = profile.coordinator } }
  18. +(MyClass *)singleton { static MyClass *shared = nil; if(shared ==

    nil) { shared = [[MyClass alloc] init]; } return shared; }
  19. +(MyClass *)singleton { static dispatch_once_t token; static MyClass *shared =

    nil; dispatch_once(&token, ^{ shared = [[MyClass alloc] init]; }); return shared; }
  20. protocol ResourceUsable { var currentResource: MyResource { get } }

    extension ResourceUsable { var currentResource: MyResource { return MyResource.default } } class MyResource { // slow, expensive object static let `default`: MyResource }
  21. class MyClient: ResourceUsable { var currentResource: MyResource = .default func

    useResource() { currentResource.performOperation() } }
  22. class ClientTest: XCTestCase { fun testSomething() { let client =

    Client() client.currentResource = fakeResource XCTAssertNotNil(client.performUpdateFromResource()) } }
  23. KVO

  24. class SomeView: UIView { var observedProgress: Progress? { didSet {

    observedProgress?.addObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted), options: [.initial, .new], context: nil) } } }
  25. class SomeView: UIView { var observedProgress: Progress? { willSet {

    observedProgress?.removeObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted), context: nil) } didSet { observedProgress?.addObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted), options: [.initial, .new], context: nil) } } }
  26. private var observingContext = 0 class SomeView: UIView { var

    observedProgress: Progress? { willSet { observedProgress?.removeObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted), context: &observingContext) } didSet { observedProgress?.addObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted), options: [.initial, .new], context: &observingContext) } } }
  27. class SomeView: UIView { //… override func observeValue(forKeyPath keyPath: String?,

    of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {} }
  28. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey

    : Any]?, context: UnsafeMutableRawPointer?) { guard &observingContext == context else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } }
  29. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey

    : Any]?, context: UnsafeMutableRawPointer?) { guard &observingContext == context else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } let value = change?[.newKey] as? Double }
  30. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey

    : Any]?, context: UnsafeMutableRawPointer?) { guard &observingContext == context else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } if let value = change?[.newKey] as? Double { renderProgress(value) //UI drawing } }
  31. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey

    : Any]?, context: UnsafeMutableRawPointer?) { guard &observingContext == context else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } if object == observedProgress && keyPath == #keyPath(Progress.fractionCompleted) { if let value = change?[.newKey] as? Double { renderProgress(value) } } }
  32. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey

    : Any]?, context: UnsafeMutableRawPointer?) { guard &observingContext == context else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } guard object == observedProgress, keyPath == #keyPath(Progress.fractionCompleted), let value = change?[.newKey] as? Double else { return } renderProgress(value) }
  33. class EasierObserving: UIView { var progress: Progress? { willSet {

    progress?.observeFractionCompleted = nil } didSet { progress?.observeFractionCompleted = renderProgress } } func renderProgress(_ value: Double) { //... } }
  34. protocol ProgressObservable { typealias ProgressReportingFunction = (Double) -> Void var

    observeFractionCompleted: ProgressReportingFunction? { get set } }
  35. class EasierObserving: UIView { var progress: ProgressObservable? { willSet {

    progress?.observeFractionCompleted = nil } didSet { progress?.observeFractionCompleted = renderProgress } } func renderProgress(_ value: Double) { //... } }
  36. class EazyProgress: ProgressObservable { let progress: Progress init(progress: Progress) {

    self.progress = progress } var observeFractionCompleted: ProgressObservable.ProgressReportingFunction? }
  37. init(progress: Progress) { self.progress = progress super.init() progress.addObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted),

    options: [.initial, .new], context: &observingContext) } deinit { progress.removeObserver(self, forKeyPath: #keyPath(progress.fractionCompleted), context: &observingContext) }
  38. extension Progress: ProgressObservable { func observeFractionCompleted(_ handler: @escaping (Double) ->

    Void) -> ProgressObservable //must keep this object to maintain connection { let observer = ProgressFractionCompletedObserver(progress: self) observer.observeFractionCompleted = handler return observer } }
  39. class Client: UIView { var observerToken: ProgressObservable! func setup() {

    let view = UIProgressView() let progress = Progress() observerToken = progress.observeFractionCompleted { view.progress = Float($0) } } }
  40. Functions are really great at calculating state Objects are really

    great at presenting state Protocols are really great at communicating state