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

Generic Networking Protocol & Name-spacing in S...

Vinh Nguyen
November 02, 2017

Generic Networking Protocol & Name-spacing in Swift

Vinh Nguyen

November 02, 2017
Tweet

More Decks by Vinh Nguyen

Other Decks in Programming

Transcript

  1. Abstract over abtraction You probably use Alamofire to abstract away

    access to URLSession and all those nasty details you don't really care about. But then, like lots of smart developers, you write ad hoc network abstraction layers. They are probably called "APIManager" or "NetworkModel", and they always end in tears. Moya's README
  2. NetworkRequest /// A shared protocol that has general shared properties

    for network response checking protocol MappableResponse: Mappable { var valid: Bool { get } var errorMessage: String { get } var statusCode: Int { get } } /// A generic enum to NetworkRequest request function protocol TargetPlaceholder: TargetType {}
  3. NetworkRequest // Base network request // Usage: conformer need to

    provide two informations. // `Model`: model that request need to parse to // `Target`: an TargetPlaceholder request route enum protocol NetworkRequest { typealias ModelCompletion = (NVResult<Model>) -> Void associatedtype Target: TargetPlaceholder associatedtype Model: MappableResponse }
  4. NetworkRequest extension NetworkRequest { func request(from provider: MoyaProvider<Target>, target: Target,

    for type: Model.Type, completion: @escaping ModelCompletion) { provider.request(target) { result in switch result { case .success(let response): do { let mappedObject = try response.mapObject(type) // ...dispatch mappedObject to `completion` } catch let responseMappingError { // ...catch ObjectMappers's error } case .failure(let moyaError): // ...handle moyaError, for example, status code, failures.. } } } }
  5. NetworkRequest Notes: + Conformers of NetworkRequest protocol API will get

    this default request method for free. + We can add other business logic in this extension, for example, handling error.
  6. class GoogleNetworkManager: NetworkRequest { // these are convenient labels typealias

    GoogleDirectionParam = [String: String] typealias ModelResponseCompletion = (NVResult<Model>) -> Void // required: this is to fill placeholder requirements from NetworkRequest typealias Model = GoogleResponse typealias Target = GoogleTarget // MARK: - Public func direction(params: GoogleDirectionParam, completion: @escaping ModelResponseCompletion) { request(from: GoogleProvider, target: Target.direction(params: params), for: Model.self, completion: completion) } }
  7. class GooglePlaceNetworkManager: NetworkRequest { // these are convenient labels typealias

    ModelResponseCompletion = (NVResult<Model>) -> Void // required: this is to fill placeholder requirements from NetworkRequest typealias Model = GooglePlaceResponse typealias Target = GoogleTarget // MARK: - Public func searchForhotelWithName(_ query: String, completion: @escaping ModelResponseCompletion) { guard query.isEmpty == false else { return } request(from: GoogleProvider, target: Target.hotelSearch(query: query), for: Model.self, completion: completion) } }
  8. Notes: — GoogleProvider is an enum that conform to Moya's

    TargetType protocol requirements. — GoogleResponse and GooglePlaceResponse are ObjectMapper models.
  9. NetworkRequest These examples illustrate simple cases, but in practice, we

    can extend the same technique to all other generic cases. https://github.com/vinhnx/iOS-notes/issues/47
  10. Namespacing in Swift In many programming languages, namespacing is a

    technique employed to avoid collisions with other objects or variables in the global namespace. They're also extremely useful for helping organize blocks of functionality in your application into easily manageable groups that can be uniquely identified. https://addyosmani.com/blog/essential-js- namespacing/
  11. Namespacing in Swift In Objective-C, we used to prefix class,

    methods, properties with unique name to avoid collision. Apple does this too, UIView, NSMangedObject, CALayer... We usually prefix with project names. In Swift, we could archieve this by annotate our API with private or fileprivate attribute.
  12. Namespacing in Swift Example in Zeplin styleguide code generator extension

    UIColor { @nonobjc class var abcWarmGrey: UIColor { return UIColor(white: 128.0 / 255.0, alpha: 1.0) } @nonobjc class var abcGreyish: UIColor { return UIColor(white: 164.0 / 255.0, alpha: 1.0) } }
  13. Namespacing in Swift extension UIColor { enum Grey { static

    var warm: UIColor { return UIColor(white: 128.0 / 255.0, alpha: 1.0) } static var grayIsh: UIColor { return UIColor(white: 164.0 / 255.0, alpha: 1.0) } } } self.backgroundColor = UIColor.Grey.warm // looks better than `UIColor.abcWarmGrey`
  14. Namespacing in Swift // Preferred // `SomeType` declared inside `SomeClass`,

    so only `SomeClass` knows about it. // This was not possible in Objective-C class SomeClass { enum SomeType { case foo, bar, baz, unknown } private var type = SomeType.unknown }
  15. // Not preferred // Declared outside of scope, so `SomeType`

    exposed // other modules can call SomeType accidentally without knowing much about inner implementations enum SomeType { case foo, bar, baz, unknown } class SomeClass { private var type = SomeType.unknown } https://github.com/vinhnx/iOS-notes/issues/50
  16. References 1. Moya: https://github.com/Moya/Moya 2. ObjectMapper: https://github.com/Hearst-DD/ ObjectMapper 3. How

    to Use Namespaces in Swift 4. Namespaced constants in Swift 5. Namespacing in Swift, also namespacing for better domain managemen 6. Generic network protocol