2017년 1월 4일 수요일

Swift 4에 추가될 사항 살펴보기

## 0142 Permit where clauses to constrain associated types

https://github.com/apple/swift-evolution/blob/master/proposals/0142-associated-types-constraints.md

associated type에 where를 쓸 수 있도록 한다.

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}

위의 문법을 허락함으로서 아래와 같이 상위 protocol의 associated type에 제한을 걸 수 있게 된다.

protocol IntSequence : Sequence where Iterator.Element == Int {
    ...
}

하지만,  아래처럼 상위 protocol에 없는 것에 제한을 걸 수는 없고,

protocol SomeSequence : Sequence where Counter : SomeProtocol { // error: Use of undefined associated type 'Counter'
    associatedtype Counter
}

아래처럼 사용되어야 한다.

protocol IntSequence : Sequence {
    associatedtype Counter : SomeProtocol
}

## 0143 - Conditional conformances

type argument가 어떤 조건을 만족하는 경우 generic type도 특정 조건에 만족하도록 한다. 예를 들어, Array의 element가 Equatable을 만족하는 경우 Array도 Equatable이 되도록 한다.

extension Array: Equatable where Element: Equatable {
  static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}

multiple conformance는 허락하지 않는다.

struct SomeWrapper<Wrapped> {
  let wrapped: Wrapped
}

protocol HasIdentity {
  static func ===(lhs: Self, rhs: Self) -> Bool
}

extension SomeWrapper: Equatable where Wrapped: Equatable {
  static func ==(lhs: SomeWrapper<Wrapped>, rhs: SomeWrapper<Wrapper>) -> Bool {
    return lhs.wrapped == rhs.wrapped
  }
}

// error: SomeWrapper already stated conformance to Equatable
extension SomeWrapper: Equatable where Wrapped: HasIdentity {
  static func ==(lhs: SomeWrapper<Wrapped>, rhs: SomeWrapper<Wrapper>) -> Bool {
    return lhs.wrapped === rhs.wrapped
  }
}

또한 상속관계에 의해서 조건의 만족이 모호해지면 안된다.

protocol P { }
protocol Q : P { }
protocol R : P { }

struct X<T> { }

extension X: Q where T: Q { }
extension X: R where T: R { }

// error: X does not conform to protocol P; add
//
//   extension X: P where <#constraints#> { ... }
//
// to state conformance to P.

하지만, 아래와 같은 경우(S < R < P)는 컴파일러가 더 일반적인(more general) 경우(R)에 대해서 내부적으로 생성하여 동작하도록 한다.

protocol R: P { }
protocol S: R { }

struct Y<T> { }

extension Y: R where T: R { }
extension Y: S where T: S { }
/// compiler produces the following implied inherited conformance:
extension Y: P where T: R { }

## 0110 - Distinguish between single-tuple and multiple-argument function types

현재는 아래처럼 one tuple argument인 경우와 multiple arguments인 경우에 대한 구별이 명백하지 않다.

let fn1 : (Int, Int) -> Void = { x in
    // The type of x is the tuple (Int, Int).
    // ...
}

let fn2 : (Int, Int) -> Void = { x, y in
    // The type of x is Int, the type of y is Int.
    // ...
}

n parameter(n > 1)인 경우에 fn2만이 맞는 표현이 되도록 한다. one tuple parameter가 n개의 요소를 가지는 경우는 아래와 같이 괄호로 감싸서 써주도록 한다.

let a : ((Int, Int, Int)) -> Int = { x in return x.0 + x.1 + x.2 }

## 0146 - Package Manager Product Definitions

## 0148 - Generic Subscripts

subscripts도 generic이 될 수 있도록 한다.

extension Dictionary {
  subscript<Indices: Sequence>(indices: Indices) -> [Iterator.Element] where Indices.Iterator.Element == Index {
    // ...
  }
}

하나 더! subscripts에 default arguments도 있도록 한다.

subscript<A>(index: A? = nil) -> Element {
    // ...
}

## 0149 - Package Manager Support for Top of Tree development

## 0150 - Package Manager Support for branches

## 0154 - Provide Custom Collections for Dictionary Keys and Values


2016년 12월 28일 수요일

RxSwift 소스 분석 - Scheduler에 대한 이해

RxSwift 소스 분석해보기

1. 기본구조이해
2. 기본구조이해 - 2
3. Scheduler에 대한 이해
4. Subject에 대한 이해

https://github.com/ReactiveX/RxSwift


Scheduler

observer callback이 실행되는 쓰레드는 observerOn으로 subscription과 unsubscription logic이 실행되는 쓰레드는 subscribeOn으로 지정할 수 있다.
'Observable+Concurrency.swift' 파일에서 extension으로 ObservableType에 지정한다.
extension ObservableType {
  public func observeOn(_ scheduler: ImmediateSchedulerType)

  public func subscribeOn(_ scheduler: ImmediateSchedulerType)
}
두 함수 모두 ImmediateSchedulerType을 파라메타로 받는다.
public protocol ImmediateSchedulerType {
  func schedule<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable
}
observeOn의 경우를 먼저 살펴보자.
scheduler가 SerialDispatchQueueScheduler인 경우에는 ObserveOnSerialDispatchQueue를 아닌 경우에는 ObserveOn을 사용한다
public func observeOn(_ scheduler: ImmediateSchedulerType) -> Observable<E> {
  if let scheduler = scheduler as? SerialDispatchQueueScheduler {
      return ObserveOnSerialDispatchQueue(source: self.asObservable(), scheduler: scheduler)
  }
  else {
      return ObserveOn(source: self.asObservable(), scheduler: scheduler)
    }
  }
ObserveOnSerialDispatchQueue를 보면 앞에서 살펴본 AnonymousObservable과 거의 유사한 구조를 가지고 있음을 알 수 있다. 차이점은 원래의 observable에다가 subscribe를 실행시키면서 ObserveOnSerialDispatchQueueSink를 파라메타로 넘겨주는 것이다. 이렇게 함으로서 원래의 observable의 subscribe handler가 실행될 때 observeer로 ObserveOnSerialDispatchQueueSink의 onCore함수가 호출되게 된다. 아래에서 보다시피 onCore에서 scheduler.schedule를 실행함으로서 scheduler에서 지정한 쓰레드에서 action이 실행되게 된다. ObserveOnSerialDispatchQueueSink의 init을 보면 cachedScheduleLambda는 사용자가 지정해준 observer를 실행하도록 되어 있는 closure이다.
init(scheduler: SerialDispatchQueueScheduler, observer: O, cancel: Cancelable) {
  self.scheduler = scheduler
  self.observer = observer
  self.cancel = cancel
  super.init()

  cachedScheduleLambda = { sink, event in
    sink.observer.on(event)

    // 코드 생략...

    return Disposables.create()
  }
}

override func onCore(_ event: Event<E>) {
    let _ = self.scheduler.schedule((self, event), action: cachedScheduleLambda)
  }
MainScheduler를 통해 schedule가 호출될 때 어떻게 동작하는지를 보자.
초기화시 _mainQueue를 DispatchQueue.main로 설정한다. schedule 호출시 호출되는 scheduleInternal를 override하여 _mainQueue.async안에서 action을 실행한다.
override func scheduleInternal<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable {
  // 자세한 코드 생략...

  _mainQueue.async {
    if !cancel.isDisposed {
      _ = action(state)
    }

    _ = AtomicDecrement(&self.numberEnqueued)
  }
}

RxSwift 소스 분석 - 기본구조이해 - 2

RxSwift 소스 분석해보기

1. 기본구조이해
2. 기본구조이해 - 2
3. Scheduler에 대한 이해
4. Subject에 대한 이해

https://github.com/ReactiveX/RxSwift

가장 기본이 되는 구조는 이벤트를 발생시키는 Observable이 있고 이것을 받아보는 Observer, 그리고 Observer가 이벤트를 받는 것을 취소할 수 있게 해주는 Disposable이 있다. 이를 코드로 구현하면 아래와 같이 된다.
public protocol ObservableType {
  associatedtype E

  func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}

public protocol ObserverType {
  associatedtype E

  func on(_ event: Event<E>)
}

public enum Event<Element> {
  case next(Element)
  case error(Swift.Error)
  case completed
}

public protocol Disposable {
  func dispose()
}
위 protocol들의 구현체로 다음의 클래스들을 만든다. ObservableType <-- Observable <-- Producer / ObserverType <-- ObserverBase / Disposable <-- Cancelable
public class Observable<Element> : ObservableType {
  public typealias E = Element

  public func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E {
    abstractMethod() // subclass에서 구현을 해서 사용하도록 한다.
  }
}

class Producer<Element> : Observable<Element> {
  override func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E {
    // 자세한 구현 생략...
    let disposer = SinkDisposer()
    let sinkAndSubscription = run(observer, cancel: disposer)
    ...
    return disposer
  }
}

class ObserverBase<ElementType> : Disposable, ObserverType {
  func on(_ event: Event<E>) {
    switch event {
    case .next:
      if _isStopped == 0 {
        onCore(event)
      }
    case .error, .completed:
      if !AtomicCompareAndSwap(0, 1, &_isStopped) {
        return
      }

      onCore(event)
    }
  }

  // ObserverBase를 상속받는 클래스는 이 함수를 구현해서 event handler를 호출하도록 한다.
  func onCore(_ event: Event<E>) {
    abstractMethod()
  }
}

public protocol Cancelable : Disposable {
  // Was resource disposed.
  var isDisposed: Bool { get }
}
Producer의 subscribe에서 ObserverType을 받아서 이를 내부에 연결시킨다. 나중에 이벤트가 발생하면 ObserverBase.on이 호출된다.
이제 이 클래스들을 기반으로 하여 원하는 기능을 구현하고 있는 클래스를 만들면 된다. 이 구현들 중 가장 간단한 AnonymousObservable, AnonymousObserver, AnonymousDisposable를 살펴보자. AnonymousObservable<Element>부터 살펴보자.
// subscription시 호출되기 위한 SubscribeHandler을 생성자에서 받아서 가지고 있고 AnonymousObservableSink를 통해 Event를 발생시킨다.
class AnonymousObservable<Element> : Producer<Element> {
  typealias SubscribeHandler = (AnyObserver<Element>) -> Disposable

  let _subscribeHandler: SubscribeHandler

  init(_ subscribeHandler: @escaping SubscribeHandler) {
    _subscribeHandler = subscribeHandler
  }

  // subscribe에서 호출해줌. sink와 subscription을 리턴
  override func run<O : ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element {
        let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
        let subscription = sink.run(self)
        return (sink: sink, subscription: subscription)
    }
}
Sink는 subscription을 위한 ObserverType이 있을 때 Event를 발생시키는 로직(on함수)이 들어가 있는 부분이다. forwardOn을 통해 observer.on을 호출하게 된다. AnonymousObservable의 경우는 AnonymousObservableSink를 통해 이 기능을 구현한다.
class Sink<O : ObserverType> : Disposable {
  final func forwardOn(_ event: Event<O.E>) {
    // 구현 생략...
  }

  func dispose() {
    // 구현 생략...
  }
}

class AnonymousObservableSink<O: ObserverType> : Sink<O>, ObserverType {
  typealias E = O.E
  typealias Parent = AnonymousObservable<E>

  // SubscribeHandler에서 observer.on을 호출하면 호출되는 함수.
  func on(_ event: Event<E>) {
    switch event {
    case .next:
      if _isStopped == 1 {
        return
      }
      forwardOn(event)
    case .error, .completed:
      if AtomicCompareAndSwap(0, 1, &_isStopped) {
        forwardOn(event)
        dispose()
      }
    }
  }

  // 여기서 Observable을 생성할 때의 SubscribeHandler를 실행한다. AnonymousObservable.run으로부터 호출된다.
  func run(_ parent: Parent) -> Disposable {
    return parent._subscribeHandler(AnyObserver(self))
  }
}

public struct AnyObserver<Element> : ObserverType {
  // observer.on을 실행하기 위해 observer.on을 내부에 저장해 놓는다.
  public init<O : ObserverType>(_ observer: O) where O.E == Element {
    self.observer = observer.on
  }

  public func on(_ event: Event<Element>) {
    // observer.on이 호출된다.
    return self.observer(event)
  }
}
보통 SubscribeHandler의 구현을 보면 필요한 이벤트 발생시 파라메터로 넘어온 observer의 on에 필요한 이벤트를 넣어서 호출해준다.
func myJust<E>(element: E) -> Observable<E> {
  return Observable.create { observer in
    observer.on(.next(element))
    observer.on(.completed)
    return Disposables.create()
  }
}

extension Observable {
  public static func create(_ subscribe: @escaping (AnyObserver<E>) -> Disposable) -> Observable<E> {
    return AnonymousObservable(subscribe)
  }
}
Observer의 전달은 다음과 같다. subscribe 함수는 파라메타로 ObserverType을 받는다. 하지만, 실제 사용자는 ObserverType을 직접 만들어서 넣어주지 않고 보통 (onNext, onCompleted, onError)를 넣어준다. 아래처럼 이것을 가지고 AnonymousObserver를 생성해서 AnonymousObservable에 이것을 넣어준다.
extension ObservableType {
  public func subscribe(onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil) -> Disposable {
    // 자세한 부분은 생략...
    ...

    // 사용자가 넣어준 (onNext, onCompleted, onError)를 가지고 AnonymousObserver를 생성한다.
    let observer = AnonymousObserver<E> { e in
      switch e {
      case .next(let value):
        onNext?(value)
      case .error(let e):
        onError?(e)
        disposable.dispose()
      case .completed:
        onCompleted?()
        disposable.dispose()
      }
    }
    return Disposables.create(self.subscribeSafe(observer), disposable)
  }
}

extension ObservableType {
  // All internal subscribe calls go through this method.
  func subscribeSafe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E {
    return self.asObservable().subscribe(observer)
  }
}

class AnonymousObserver<ElementType> : ObserverBase<ElementType> {
  typealias Element = ElementType

  typealias EventHandler = (Event<Element>) -> Void

  private let _eventHandler : EventHandler

  init(_ eventHandler: @escaping EventHandler) {
    _eventHandler = eventHandler
  }

  override func onCore(_ event: Event<Element>) {
    return _eventHandler(event)
  }
}
정리하면 Observable의 subscribe에 핸들러를 등록하면 [Producer.subscribe -> AnonymousObservable.run -> AnonymousObservableSink.run -> AnonymousObservable.subscribeHandler -> ObserverType.on -> AnonymousObserver.onCore]를 통해 지정해준 핸들러가 호출된다. 결국 최종적으로 사용자가 subscribe에 넣어준 (onNext, onCompleted, onError)가 호출되게 되는 것이다.
마지막으로 Observer를 취소하고 싶으면 subscribe의 리턴값인 Disposable의 dispose 함수를 호출해 주면 된다.
fileprivate class SinkDisposer: Cancelable {
  // sink와 subscription을 중단시킨다. sink에 dispose를 호출하면 observer의 on이 호출되지 않는다.
  // subscription에 dispose를 호출하면 SubscribeHandler를 중단시킬 수 있다.
  func dispose() {
    // 자세한 구현은 생략
    sink.dispose() // 
    subscription.dispose()
  }
}
AnonymousObservableSink가 상속하는 Sink에 dispose가 구현되어 있다.
class Sink<O : ObserverType> : Disposable {
  fileprivate var _disposed: Bool

  // on 함수가 호출되어 observer를 호출하기 전에 dispose 여부를 확인하여 실행할지 안할지를 결정한다.
  final func forwardOn(_ event: Event<O.E>) {
    if _disposed {
      return
    }
    _observer.on(event)
  }

  func dispose() {
    _disposed = true
    _cancel.dispose()
  }
}

RxSwift 소스 분석 - 기본구조이해

RxSwift 소스 분석해보기

1. 기본구조이해
2. 기본구조이해 - 2
3. Scheduler에 대한 이해
4. Subject에 대한 이해

https://github.com/ReactiveX/RxSwift

기초 이해

시작하기 위한 초간단 아이템 호출 구조

  • Observable.create를 통해 Observable<E>를 생성한다. -> AnonymousObservable이 생성된다. ObservableType+Creation.swift
extension Observable {
  // element가 없는 AnonymousObservable을 생성한다.
  public static func create(_ subscribe: @escaping (AnyObserver<E>) -> Disposable) -> Observable<E> {
    return AnonymousObservable(subscribe)
  }
}
  • AnonymousObservable에 subscribeHandler를 넘겨준다. -> subscribeHandler는 (AnyObserver<E> -> Disposable)이다.
class AnonymousObservable<Element> : Producer<Element> {
  let _subscribeHandler:  SubscribeHandler

  // 내부에 SubscribeHandler를 저장
  init(_ subscribeHandler: @escaping SubscribeHandler) {
    _subscribeHandler = subscribeHandler
  }
}
  • 생성된 Observable에 subscribe를 하면 내부에서 Producer의 subscribe를 호출한다. -> AnonymousObservable은 Producer를 상속한다. ObservableType+Extensions.swift
extension ObservableType {
  public func subscribe(onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil) -> Disposable {
    ...
    // self.asObservable().subscribe(observer)를 호출한다.
    // observer는 사용자가 지정해준 onNext, onError등을 Event에 따라 실행해주는 AnonymousObserver이다.
  }
}
  • Producer의 subscribe에서 AnonymousObservable의 run을 호출한다.
class Producer<Element> : Observable<Element> {
  override func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == Element {
    // scheduler에서 AnonymousObservable의 run을 실행한다.
  }
}
  • AnonymousObservableSink의 run을 호출하여 subscribeHandler를 호출한다. subscribeHandler는 사용자가 넣어준 handler인데 조건에 따라 observer의 on을 호출한다.(AnyObserver를 통한 forwarding -> AnonymousObservableSink.on -> AnonymousObserver.on)
class AnonymousObservable<Element> : Producer<Element> {
  override func run<O : ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element {
    // AnonymousObservableSink의 run을 호출한다.
  }
}

class AnonymousObservableSink<O: ObserverType> : Sink<O>, ObserverType {
  func on(_ event: Event<E>) {
    // AnonymousObserver를 통해 사용자가 넣어준 onNext, onError등의 함수를 호출한다.
  }

  func run(_ parent: Parent) -> Disposable {
    // observable을 생성할 때 넣어준 SubscribeHandler를 호출한다.
    // SubscribeHandler 안에서 observer.on을 호출하면 위의 on 함수가 호출된다.
  }
}

Subscription에 대한 취소 구조

  • subscription을 호출하면 이에 대해 Disposable을 리턴한다. -> Disposable은 SinkDisposer이다.
class Producer<Element> : Observable<Element> {
  override func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == Element {
    let disposer = SinkDisposer()
    ...
    return disposer
  }
}
  • AnonymousObservable의 run을 실행할 때 파라메터로 SinkDisposer를 넘겨주어서 AnonymousObservableSink도 SinkDisposer를 같이 바라보게 한다.
  • SinkDisposer는 sink와 subscription을 가지고 있는다.
    • subscribe: _subscribeHandler의 리턴
    • sink: event를 실행하는 AnonymousObservableSink
  • 사용자가 subscription을 cancel하고 싶으면 Disposable.dispose를 호출한다.
    • sink와 subscription 각각에 dispose를 호출한다.
    • sink에 dispose가 불리게 되면 observer의 on이 불리지 않게 된다. -> observer.on의 호출 전 dispose 여부 확인
    • subscription에 dispose가 불리게 되면 observable을 만들때의 subscription handler의 구현에 따라 관련 내용이 취소되도록 한다: ex) 네트워크 요청이 취소되도록 한다. 타이머가 중단되도록 한다.

Scheduler를 사용하는 경우의 구조

  • observeOn을 사용해서 observer가 실행되는 scheduler를 지정할 수 있다.
  • observeOn의 리턴은 원래의 observable과 scheduler를 가지고 있는 ObserveOnSerialDispatchQueue이다.
  • ObserveOnSerialDispatchQueue는 sink로는 ObserveOnSerialDispatchQueueSink를, subscription으로는 원래의 source에 subscribe한것을 갖는다.
  • 결국 사용자가 subscribe를 실행하면 ObserveOnSerialDispatchQueueSink가 불리게 되는데 여기서 scheduler를 통해 원래의 observer를 event를 통해 실행한다.

Simple UITextField bindings

  • text property를 위한 reactive wrapper를 만든다.
public var text: ControlProperty<String?> {
  return UIControl.rx.value(...)
}
  • UIControl.rx.value에서 Observable.create를 써서 observable을 만들고 UIBindingObserver의 bindingObserver를 사용해서 최종적으로 ControlProperty를 만든다.
  • ControlProperty는 ObservableType이고 ObserverType이다.

2016년 12월 22일 목요일

Alamofire에서 사용하는 Queue에 대한 정리


  • SessionManager의 backgroundCompletionHandler
    • background transfer가 끝났을 때 'DispatchQueue.main.async'로 실행된다.
  • Upload
    • 정상적인 경우의 실행은 'DispatchQueue.global(qos: .utility).async' 로 이루어진다.
    • encodingCompletion은 정상적으로 upload가 완료되었을 때나 중간에 에러가 발생했을 때에나 항상 'DispatchQueue.main.async'에서 실행된다.
  • Retry
    • (request, download, upload)중 에러가 발생하면 allowRetrier를 호출하는데 이 함수의 내용은 'DispatchQueue.global(qos: .utility).async'를 통해 asynchronous로 실행된다. 그리고 should() 함수의 completionHandler의 구현에서 retry를 'DispatchQueue.global(qos: .utility).asyncAfter()'에서 실행한다.
    • URLSession으로부터의 응답이 에러를 포함하고 있어 retry를 확인하는 경우 retrier.should()의 completionHandler가 'DispatchQueue.global(qos: .utility).asyncAfter()' 에서 실행된다.
  • Request
    • 서버 요청을 위한 task(dataTask, downloadTask, uploadTask)를 만들 때 queue를 parameter로 받아서 'queue.syncResult' 로 실행하여 task를 생성한다. parameter로 받는 queue는 SessionManager에서 'DispatchQueue(label: "org.alamofire.session-manager." + UUID().uuidString)' 로 고정되어 있다.
  • Response
    • response handler가 기본으로 실행되는 queue는 'DispatchQueue.main'이다. 하지만 사용자가 지정할 수 있다. async로 호출한다.
  • progress handler
    • 기본은 'DispatchQueue.main'이다. 하지만, 사용자가 직접 queue를 지정해 줄 수 있다. async로 호출한다.

Generic interfaces 요점

 https://go.dev/blog/generic-interfaces  Generic interface를 정의할 때 최소한의 제약만을 정의하고 실제 구현체들이 자신만의 필요한 제약을 추가할 수 있도록 하는 것이 좋다. pointer receiver를...