Skip to content

Latest commit

 

History

History
89 lines (67 loc) · 4.35 KB

File metadata and controls

89 lines (67 loc) · 4.35 KB

Side Effets: The Point

  • 가장 복잡한 asyncrhonous side effect를 추출하였다.
  • 하지만 몇 가지의 이유로 인하여 이 effect는 더욱 복잡해 졌다.
    • 이전에는 고려하지 않았던 alert의 표시와 해제와 결합되어져 있다.
      • 이 문제를 해결하려면 alert의 표시와 관련된 local state를 추출하는 것이 의미하는 바, 바인딩 관리 방법, 해제 등을 고려해야했다.
    • 그 effect가 asynchronous하기 때문이다.
      • Asynchronous는 synchronous effect보다 본질적으로 더 복잡하다.
      • Threading 문제를 고려해야했지만, 이것은 View에서 ObservableObject로 로직을 추출하는 모든 사람이 직면하게되는 문제이다. 고로, 아키텍쳐의 결함이 아니다.
  • 새로운 Effect는 Parallel과 같은 모양으로, 다른 사람에게 함수를 전달하고, 작업을 수행하고 준비가되면 해당 함수를 호출한다.
  • Strore에 다시 피드백될 수 있는 배열로 effect를 반환할 수 있는 Reducer를 가지고 있다.
  • Unidirectional data flow를 수용할 수 있게 되었다.
    • Effect와 asynchronicity에 의하여 발생하는 복잡성이 있지만, 어떻게 데이터가 어플리케이션을 통과하는 지에 대하여 추론할 수 있다.
    • Effect는 오로지 store를 통하여 다시 전송되는 action을 통해서만 app의 state를 변경한다
  • Side-effect 코드가 view의 clousre에 존재하는 것이 아니라, 이제는 reducer의 closure 안에 존재한다.
  • (@escaping (A) -> Void) -> Void 의 signature를 감싸는 struct를 만든다.
  • Effect는 일부 callback 함수를 통해 async적으로 수행 할 수있는 작업 단위이다.
  • 그리고 map operation을 지원하여 effect에 의해 생성되는 값을 다른 값으로 쉽게 변환 할 수 있다.
public struct Effect<A> {
  public let run: (@escaping (A) -> Void) -> Void

  public init(run: @escaping (@escaping (A) -> Void) -> Void) {
    self.run = run
  }

  public func map<B>(_ f: @escaping (A) -> B) -> Effect<B> {
    return Effect<B> { callback in self.run { a in callback(f(a)) }
  }
}
  • Wolfram Alpha를 처리하기위한 라이브러리 코드가 여전히 Effect 유형을 사용하는 대신 콜백 세계에 살고 있으며, Wolfram API와의 상호 작용과 관련이없는 몇 가지 보편적인 것들과 Wolfram 특정 도메인에 해당하는 URLSession의 요청, JSON 디코딩이 혼합되어 있다.
  • Wolfram에 대한 것이 Effect 타입으로 표현되는 것은 좋지만 작업의 단위를 더욱 쉽게 분해할 수 있다.
public typealias DataTaskResopnse = (Data?, URLResponse?, Error?)

extension URLSession {
    
    public func dataTask(request: URL) -> Effect<DataTaskResopnse> {
      return Effect { callback in
        self.dataTask(with: request) { data, response, error in
          callback((data, response, error))
        }.resume()
      }
    }

}

extension Effect where A == DataTaskResopnse {
    
    public func decode<B: Decodable, D: TopLevelDecoder>(
        as type: B.Type,
        using decoder: D
    ) -> Effect<B?> where D.Input == Data {
    return self.map { data, _, _ in
      data
        .flatMap { try? decoder.decode(B.self, from: $0) }
    }
  }
    
}
  • nthPrime(count).map { CounterAction.nthPrimeResponse($0) } 는 action을 보낼 때, main에서 수행하도록 할 수가 없다.
public func receive(on queue: DispatchQueue) -> Effect {
        return Effect { callback in
            self.run { a in queue.async { callback(a) }
            }
        }
    }