Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Mobile Fest 2018. Александр Корин. Болеутоляющее

64 views

Published on

Наш код - это наша боль. Как бы крут он не был, как бы хорошо не был написан, возвращаясь к нему через год мы ощущаем стыд за то, что мы натворили. За несколько лет сей стыд перерастает в боль за бессмыссленно потраченное время жизни. Мы обсудим болеутоляющие, данные нам возможностями Swift и моим больным воображением

Published in: Education
  • Be the first to comment

  • Be the first to like this

Mobile Fest 2018. Александр Корин. Болеутоляющее

  1. 1. Pain Reliever
  2. 2. Pain Reliever
  3. 3. Pain Reliever
  4. 4. Pain Reliever
  5. 5. Pain Reliever
  6. 6. Pain Reliever
  7. 7. Don't mess with recruiters
  8. 8. Atomic
  9. 9. 9 extension NSLocking func `do`<Result>( action: () -> Result ) -> Result { self.lock() defer { self.unlock() } return action() } Atomic
  10. 10. 10 protocol Lockable: NSLocking { } extension NSLock: Lockable { } extension NSRecursiveLock: Lockable { } Atomicclass Atomic<Wrapped>
  11. 11. 11 typealias Value = Wrapped typealias Observer = ((old: Value, new: Value)) -> () Atomicclass Atomic<Wrapped>
  12. 12. 12 func modify<Result>( _ action: (inout Value) -> Result ) -> Result { return self.lock.do { let oldValue = self.mutableValue defer { self.observer?((oldValue, self.mutableValue)) } return action(&self.mutableValue) } } Atomicclass Atomic<Wrapped>
  13. 13. 13 func transform<Result>( _ action: (Value) -> Result ) -> Result { return self.lock.do { action(self.mutableValue) } } Atomicclass Atomic<Wrapped>
  14. 14. 14 static func recursive(_ value: Value, observer: Observer? = nil) -> Atomic<Value> static func lock(_ value: Value, observer: Observer? = nil) -> Atomic<Value> Atomicclass Atomic<Wrapped>
  15. 15. 15 var value: Value { get { return self.transform { $0 } } set { self.modify { $0 = newValue } } } Atomicclass Atomic<Wrapped>
  16. 16. 16 struct ID { let value: Int init(_ value: Int) { self.value = value } init?(string: String) { guard let value = Int(string) else { return nil } self.init(value) } } Atomic
  17. 17. 17 extension ID: Comparable extension ID: Hashable extension ID: CustomStringConvertible extension ID: ExpressibleByIntegerLiteral Atomic
  18. 18. 18 extension ID { typealias Provider = () -> ID } Atomic
  19. 19. 19 func autoincrementedID( _ start: Int, didSet: ((_ newValue: Int) -> ())? = nil ) -> ID.Provider { let value = Atomic.lock(start) return { value.modify { let result = $0 $0 += 1 didSet?($0) return ID(result) } } } Atomic
  20. 20. 20 func autoincrementedID(start: Int) -> ID.Provider { return autoincrementedID(start) } Atomic
  21. 21. 21 let provider = autoincrementedID(10) provider() // ID(10) provider() // ID(11) Atomic
  22. 22. 22 extension UserDefaults { func write(_ action: (UserDefaults) -> ()) { action(self) self.synchronize() } } Atomic
  23. 23. 23 Atomic fileprivate let persistentProviders = Atomic.lock( [String: ID.Provider]() ) func autoincrementedID(key: String) -> ID.Provider { return persistentProviders.modify { storage in storage[key] ?? call { let defaults = UserDefaults.standard let start = defaults.integer(forKey: key) let result = autoincrementedID(start) { id in defaults.write { $0.set(id, forKey: key) } } storage[key] = result return result } } }
  24. 24. 24 Atomic let provider = autoincrementedID(key: "mama") provider() // ID(0) provider() // ID(1)
  25. 25. Atomic
  26. 26. Cancellable
  27. 27. Cancellable 27 protocol Cancellable { func cancel() }
  28. 28. Cancellable 28 class CancellableProperty<Value: Cancellable> { public var value: Value? { willSet { value?.cancel() } } }
  29. 29. Cancellable 29 struct Request: Cancellable struct Service { let request = CancellableProperty<Request>() } service.request.value = Request()
  30. 30. Cancellable 30 infix operator <~ : AssignmentPrecedence prefix operator ^ postfix operator ^
  31. 31. Cancellable 31 protocol Wrappable: AnyObject { associatedtype Wrapped var value: Wrapped { get set } static func <~(wrapper: Self, value: Self.Wrapped) prefix static func ^(wrapper: Self) -> Self.Wrapped postfix static func ^(wrapper: Self) -> Self.Wrapped }
  32. 32. Cancellable 32 static func <~(wrapper: Self, value: Self.Wrapped) { wrapper.value = value } prefix static func ^(wrapper: Self) -> Self.Wrapped { return wrapper.value } postfix static func ^(wrapper: Self) -> Self.Wrapped { return wrapper.value } extension Wrappable
  33. 33. Cancellable 33 extension CancellableProperty: Wrappable { } service.request <~ Request() let request = ^service.request service.request^.do { $0.cancel() }
  34. 34. Cancellable 34 extension Wrappable where Self.Wrapped: Wrappable { static func <~(wrapper: Self, value: Wrapped.Wrapped) { wrapper.value <~ value } prefix static func ^(wrapper: Self) -> Wrapped.Wrapped { return ^wrapper.value } postfix static func ^(wrapper: Self) -> Wrapped.Wrapped { return ^wrapper.value } }
  35. 35. Cancellable 35 extension Atomic: Wrappable { } let request = Atomic.lock(CancellableProperty<Request>()) request <~ Request()
  36. 36. Cancellable
  37. 37. Conventions
  38. 38. Conventions 38 enum Image { } extension Image { enum Login: String, ImageRepresentable { case logo = "nope.jpg" case image } }
  39. 39. Conventions 39 // nope.jpg imageView.image = Image.Login.logo.opaque // login_image.jpg imageView.image = Image.Login.image.sized(.full)
  40. 40. Conventions 40 func identity<T>(_ value: T) -> T { return value } extension Sequence { var array: [Element] { return self.map(identity) } }
  41. 41. Conventions 41 extension Sequence where Element: Hashable { var set: Set<Element> var uniqueArray: [Element] }
  42. 42. Conventions 42 extension Sequence where SubSequence: Sequence { typealias Neighbours = ( current: SubSequence.Element, previous: Element ) func neighbourElements() -> [Neighbours] { return zip(self.dropFirst(), self).array } }
  43. 43. Conventions 43 func split(by comparator: Character.Comparator) -> [String] { let characterIndices = self .filter(comparator) .flatMap(self.index) let border = [self.startIndex, self.endIndex] let indices = border + characterIndices return indices .uniqueArray .sorted() .neighbourElements() .map { String(self[$0.previous..<$0.current]) } } extension String
  44. 44. Conventions 44 extension Character { typealias Comparator = (Character) -> Bool func isUppercase() -> Bool { let string = String(self) return string == string.uppercased() } }
  45. 45. Conventions 45 "mamaPapaDedaBaba".split { $0.isUppercase() }
  46. 46. Conventions 46 infix operator §: ApplicationPrecedence func § <Value, Result>( function: (Value) -> Result, value: Value ) -> Result { return function(value) }
  47. 47. Conventions 47 prefix operator ∑-> prefix func ∑-> <Type, Result>( _ function: @escaping (Type) -> () -> Result ) -> (Type) -> Result { return { function § $0 § () } }
  48. 48. Conventions 48 func • <A, B, C>( lhs: @escaping (A) -> B, rhs: @escaping (B) -> C ) -> (A) -> C { return { rhs(lhs § $0) } }
  49. 49. Conventions 49 ["mama", "papa"].map( ∑->String.uppercased • ∑->String.dropFirst • String.init )
  50. 50. Conventions 50 infix operator §-> : CompactPrecedence func §-> <Type, Arguments, Result>( _ function: @escaping (Type) -> (Arguments) -> Result, arguments: Arguments ) -> (Type) -> Result { return { function § $0 § arguments } }
  51. 51. Conventions 51 protocol ImageRepresentable { var opaque: UIImage? { get } func sized(_ size: Image.Size) -> UIImage? }
  52. 52. Conventions 52 extension ImageRepresentable where Self: RawRepresentable, Self.RawValue == String { var opaque: UIImage? { return UIImage(named: self.name) } func sized(_ size: Image.Size) -> UIImage? { return self.opaque.flatMap(UIImage.resize §-> size) } }
  53. 53. Conventions 53 extension ImageRepresentable { private var name: String { return self.shouldOverrideConvention ? self.conventionName : self.rawValue } private var conventionName: String { return [typeString § self, self.rawValue] .flatMap(String.split §-> ∑->Character.isUppercase) .map(∑->String.lowercased) .joined(separator: "_") } private var shouldOverrideConvention: Bool { return "(self)" == self.rawValue } }
  54. 54. Conventions 54 extension CGRect { var x: CGFloat var y: CGFloat var width: CGFloat var height: CGFloat } extension CGSize { var min: CGFloat func scaled(by scale: CGFloat) -> CGSize }
  55. 55. Conventions 55 extension Image { enum Size: String { case thumb case small case medium case large case full } }
  56. 56. Conventions 56 static var all: [Image.Size] { return [.thumb, .small, .medium, .large, .full] } extension Image.Size
  57. 57. Conventions 57 var dimension: CGFloat? { let screen = UIScreen.main let dimension = screen.bounds.size.min * screen.scale switch self { case .thumb: return dimension / 8 case .small: return dimension / 4 case .medium: return dimension / 2 case .large: return dimension case .full: return nil } } func multiplier(for size: CGSize) -> CGFloat { return self.dimension.map { $0 / size.min } ?? 1 } func size(for size: CGSize) -> CGSize { return size.scaled § self.multiplier(for: size) } extension Image.Size
  58. 58. Conventions 58 label.text = NSLocalizedString( "label_content_identifier", comment: "localized" ) extension String { var localized: String { return NSLocalizedString(self, comment: "") } } label.text = "label_content_identifier".localized
  59. 59. Conventions 59 enum Strings: String, LocalizedStringConvertible { case ok case cancel enum Login: String, LocalizedStringConvertible { case login = "signin" } }
  60. 60. Conventions 60 protocol RawStringRepresentable: CustomStringConvertible { } extension RawStringRepresentable where Self: RawRepresentable, Self.RawValue: CustomStringConvertible { var description: String { return self.rawValue.description } }
  61. 61. Conventions 61 protocol LocalizedStringConvertible: RawStringRepresentable { var localizedDescription: String { get } var localizationIdentifier: String { get } } extension LocalizedStringConvertible { var localizedDescription: String { return NSLocalizedString( self.localizationIdentifier, comment: "" ) } var localizationIdentifier: String { return "(typeString § self).(self)".lowercased() } }
  62. 62. Conventions 62 label.text = Strings.cancel.localizedDescription
  63. 63. Conventions
  64. 64. Thanks! https://www.idapgroup.com/blog https://github.com/trimmurrti/Talks

×