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

some<T:Generic> () -> Sugar

some<T:Generic> () -> Sugar

Talk by Andrii Andreiev

Разговор пойдет о типах и программировании в терминологии типов. Когда и зачем применять generic подходы. Как получить максимальную пользу от generics в повседневной разработке

This talk was made for CocoaFriday #3 ( https://cocoaheads.org.ua/cocoafriday/3 ) which took place May 10, 2019

Video: https://youtu.be/HdNZaPLKkpM

CocoaHeads Ukraine

May 10, 2019
Tweet

More Decks by CocoaHeads Ukraine

Other Decks in Technology

Transcript

  1. P R O L O G U E S M

    A L L ( j u s t 1 s l i d e ) PA R T
  2. T H E O R Y B O R I

    N G ( I k n o w ) PA R T
  3. convention T - Type E - Element (in collections) K

    - Key (in dictionaries) V - Value (in dictionaries) N - Number U, V, S - 2nd, 3rd, 4th types func funcName<T>(arg: T) -> T { return arg }
  4. easy: @examles (Sequence<Type>) -> Void var arr = Array<String>() var

    arr = [String]() var set = Set<Int>() var dict = Dictionary<String, String>() var dict = [String : String]()
  5. theory: constraints func funcName<T> (_ arg: T) -> Int {

    … } func funcName<T> (_ arg: T) -> Int where T: SomeClass { … } func funcName<T: SomeProtocol> (_ arg: T) -> Int { … } func funcName<T: SomeProtocol> (_ arg: T) -> Int where T: SomeClass { … } func funcName<T: SomeClass&SomeProtocol> (_ arg: T) -> Int { … } typealias SomeT = SomeClass&SomeProtocol func funcName<T: SomeT> (_ arg: T) -> Int { … }
  6. theory: multiple types class SomeClass { var value: Int =

    0 } protocol SomeProtocol { func calculate(_ arg: Int) -> CGFloat } func funcName<T: SomeClass, U: SomeProtocol>(_ a: T, _ b: U) -> CGFloat { return b.calculate(a.value) }
  7. more specifics: struct and class struct GenericStruct<T> { var property:

    T? } class GenericClass<T> { var property: T? init(){} init(property: T?) { self.property = property } } // T is Bool let explicitStruct = GenericStruct<Bool>() let explicitClass = GenericClass<Bool>() // T is String let implicitStruct = GenericStruct(property: "Bob") let implicitClass = GenericClass(property: “Bob")
  8. more specifics: protocol protocol GenericProtocol<T> { var property: T {

    get set } } protocol GenericProtocol { associatedtype T var property: T { get set } } ✘ ✔ associated type = typealias + generic
  9. protocol GProt { associatedtype AType: Comparable var property: AType {

    get set } } func func1<T>(a: T) -> Int where T: GProt, T.AType: Codable { return 0 } func func2<T: GProt, U: GProt>(a: T, b: U) -> Bool where T.AType == U.AType { return a.property == b.property } more specifics: protocol
  10. P R A C T I C E F U

    N ( I h o p e ) PA R T
  11. practice: Self, chaining, extension import UIKit extension UIView { @discardableResult

    func add(to parent: UIView) -> Self { parent.addSubview(self) return self } } touchIdBtn.add(to: self).pin.left().vCenter()
  12. practice: XibLoadable extension XibLoadable where Self: UIView { static func

    fromXib() -> Self? { //helper generic func func instantiateXib<T: UIView>() -> T? { let name = String(describing: self) let nib = UINib(nibName: name, bundle: nil) print(self, T.self) let instance = nib.instantiate(withOwner: self, options: nil) return instance.first as? T } return instantiateXib() } }
  13. extension XibLoadable where Self: UIViewController { static func fromXib() ->

    Self? { //helper generic func func instantiateXib<T: UIViewController>() -> T? { return T(nibName: String(describing: T.self), bundle: nil) } return instantiateXib() } } practice: XibLoadable
  14. practice: Coordinator private typealias ScreenType = ScreenVC<LoginGroupCoordinator>&XibLoadable private func push<T:ScreenType>(_

    vcType: T.Type, animated: Bool = true) { guard let vc: T = .fromXib() else {return} vc.coordinator = self self.navigationController.pushViewController(vc, animated: animated) } func createAccount() { self.push(CreateAccountVC.self) }
  15. JSON parsing struct Feed<SomeMetadata: Codable, SomeData: Codable>: Codable { var

    meta: SomeMetadata? var data: [SomeData] var id: Int enum CodingKeys: String, CodingKey { case meta, data case id = "identifier" } }
  16. JSON parsing struct MyData: Codable { var type: String var

    id: Int var attributes: Attributes } struct MyMetadata: Codable { var type: String var attributes: MetaAttributes var id: Int } struct Attributes: Codable { var title: String var body: String var created: String var updatet: String } struct MetaAttributes: Codable { var name: String var age: Int var gender: String }
  17. JSON parsing let urlString = "https://example.com/api_v1/data?param1=value1&param2=value2" guard let url =

    URL(string: urlString) else { return } let request = URLRequest(url: url) let task = URLSession.shared.dataTask(with: request) { data, response, error in if let data = data { let decoder = JSONDecoder() do { let feed = try decoder.decode(Feed<MyMetadata, MyData>.self, from: data) // success code } catch { print("error trying to convert data to JSON") print(error) // failure code } } } task.resume()
  18. Nested <Generic> Types struct Task<Input, Output> { typealias Closure =

    (Input) throws -> Output let closure: Closure } extension Task { enum Result { case success(Output) case failure(Error) } func run(input: Input) -> Result { do { let output = try self.closure(input) return .success(output) } catch { return .failure(error) } } }
  19. Nested <Generic> Types typealias Input = Data? struct DecodeTask<Output: Decodable>

    { enum Result { case success(Output) case failure(Error) } func run(input: Input) -> Result { guard let data = input else { return .failure(DecodeError.inputIsNil) } let decoder = JSONDecoder() do { let output = try decoder.decode(Output.self, from: data) return .success(output) } catch { return .failure(error) } } } let result = DecodeTask<MyData>().run(input: someData)
  20. Collection <Bonus> func value<T>(forKey key: String) -> T? { let

    def = UserDefaults.standard return def.value(forKey: key) as? T }
  21. Collection <Bonus> typealias IterateBoby = (_ label:String?,_ value:Any) -> Void

    func iterate<Tuple>(_ tuple:Tuple, body: IterateBoby) { for child in Mirror(reflecting: tuple).children { body(child.label, child.value) } }
  22. Collection <Bonus> extension Data { init<T>(from value: T) { self

    = Swift.withUnsafeBytes(of: value) { Data($0) } } }
  23. Collection <Bonus> extension BinaryFloatingPoint { static var e: Self {

    return 2.71828182845904523536028747135266249775724709369995 } } print(Float32.e) //2.7182817 print(Float64.e) //2.718281828459045 print(Float80.e) //2.7182818284590452354 print(Double.e) //2.718281828459045
  24. Collection <Bonus> infix operator ^^ public func ^^ <T: Numeric>(

    value: T, power: Int) -> T { var finalValue: T = 1 for _ in 0..<power { finalValue = finalValue * value } return finalValue }