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

Db84cf61fdada06b63f43f310b68b462?s=128

CocoaHeads Ukraine

May 10, 2019
Tweet

Transcript

  1. some<T:Generic>() -> Sugar ANDRII ANDREIEV

  2. 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
  3. 69 kamasutra VS retain cycle

  4. T H E O R Y B O R I

    N G ( I k n o w ) PA R T
  5. …in terms of Type Types Named Compound protocol enum struct

    class function tuple { model types
  6. 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 }
  7. 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]()
  8. 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 { … }
  9. 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) }
  10. 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")
  11. more specifics: protocol protocol GenericProtocol<T> { var property: T {

    get set } } protocol GenericProtocol { associatedtype T var property: T { get set } } ✘ ✔ associated type = typealias + generic
  12. 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
  13. P R A C T I C E F U

    N ( I h o p e ) PA R T
  14. 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()
  15. protocol XibLoadable { static func fromXib() -> Self? } practice:

    XibLoadable
  16. 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() } }
  17. 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
  18. practice: Coordinator class ScreenVC<T:Coordinator>: UIViewController { var coordinator: T? }

  19. 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) }
  20. practice: JSON parsing

  21. 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" } }
  22. 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 }
  23. 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()
  24. 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) } } }
  25. 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)
  26. Collection <Bonus> func value<T>(forKey key: String) -> T? { let

    def = UserDefaults.standard return def.value(forKey: key) as? T }
  27. 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) } }
  28. Collection <Bonus> extension Data { init<T>(from value: T) { self

    = Swift.withUnsafeBytes(of: value) { Data($0) } } }
  29. 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
  30. 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 }
  31. Thnx СПАСИБО ЗА ВНИМАНИЕ