├── README.md ├── SimpleReactiveSwift.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── jeonyeohun.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── jeonyeohun.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist └── SimpleReactiveSwift ├── AnonymousObservable.swift ├── AnonymousObservableSink.swift ├── AnonymousObserver.swift ├── AnyObserver.swift ├── Cancelable.swift ├── Disposables.swift ├── Event.swift ├── Observable.swift ├── ObservableConvertibleType.swift ├── ObservableType.swift ├── ObserverBase.swift ├── ObserverType.swift ├── Producer.swift ├── Sink.swift ├── SinkDisposer.swift └── main.swift /README.md: -------------------------------------------------------------------------------- 1 | # 읽다보면 이해가 되는 알엑스 👀 2 | 3 | ## Intro 4 | 익명 Observable, 익명 Observer만 존재하는 간단한 리액티브를 구현하는 저장소입니다.

5 | 6 | [공식 레포](https://github.com/ReactiveX/RxSwift)의 코드를 최대한 따라가면서, 기본적인 기능을 제공하는 코드를 제외하고는 삭제하여 리액티브 프로그래밍의 원리를 이해하는데 집중합니다. 7 | 8 |
9 | 10 | main.swift에서부터 주석을 따라가다보면 어떻게 subscribe와 이벤트의 전달과 처리가 동작하는지 이해하게 됩니다 😎
11 | 주석은 **여행 #** 으로 넘버링 되어 있습니다. XCode의 검색을 "여행"으로 고정해두면 다음 파일을 찾기가 편합니다. 12 | 13 | ex) 14 | ```swift 15 | /* 여행 1 */ 16 | // create에 들어가는 클로저의 타입은 (AnyObserver) -> Disposable) -> Observable. 17 | // observer 혹은 emitter로 써오던 파라미터가 결국 AnyObserver였음을 알 수 있다. AnyObserver에 onNext나 onComplete 같은 이벤트를 방출해주는 것 18 | // create의 반환 타입은 Observable. 즉, create는 말 그대로 observable을 만드는 메서드이고, 만들 때 내부에 방출할 이벤트를 전달해준다. 19 | // 전달되는 클로저의 반환타입은 disposable이다. 그래서 Disposables.create를 호출해준다. create에 클로저가 전달되면 dispose가 호출되었을 때 그 클로저를 실행한다. 20 | // 그럼 create 메서드를 더 자세히 보자. Observable.create가 있는 곳으로 이동하자. create에 우클릭하고 jump to definition 고고 21 | let observable = Observable.create { observer in 22 | 23 | /* 여행 19 */ 24 | // 클로저에 왔다. 이곳에 전달된 observer는 AnyObserver였다. onNext를 찾아가자. 25 | observer.onNext(1) 26 | observer.onNext(2) 27 | observer.onCompleted() 28 | return Disposables.create() 29 | } 30 | ``` 31 | 32 |
33 | 34 | ## 제공하는 기능 35 | - Observable 생성 36 | - 이벤트는 next, error, completed 만 지원 37 | - 생성한 Observable 구독 38 | - 구독 취소 39 | 40 |
41 | 42 | ## 이해하고자 하는 객체들 43 | 44 | ### [AnonymousObservable](https://github.com/ReactiveX/RxSwift/blob/b4307ba0b6425c0ba4178e138799946c3da594f8/RxSwift/Observables/Create.swift#L64) 45 | 46 | - AnonymousObservable은 create를 통해 새로운 Observable을 생성할 때 반환되는 인스턴스 입니다. 47 | - AnonymousObservable은 생성자로 subscribeHandler를 받습니다. 이 핸들러는 AnonymousObservable 인스턴스에 대한 구독(subscribe)가 발생하면 실행됩니다. 48 | 49 | ```swift 50 | init(_ subscribeHandler: @escaping SubscribeHandler) { 51 | self.subscribeHandler = subscribeHandler 52 | } 53 | ``` 54 | 55 | - 따라서 create 메서드와 함께 전달하는 클로저가 subscribeHanlder에 저장됩니다. 56 | 57 | ```swift 58 | let observable = Observable.create { observer in // 이 trailing closure가 subscribeHandler에 저장된다. 59 | observer.onNext(1) 60 | observer.onNext(2) 61 | observer.onCompleted() 62 | return Disposables.create() 63 | } 64 | ``` 65 | - AnonymousObservable은 Producer 클래스를 상속합니다. 따라서 subscribe가 발생하면 Producer의 subscribe가 호출되고, AnonymousObservable은 Producer의 run 메서드를 오버라이딩해 정의합니다. run 메서드는 sink와 subscription 인스턴스를 생성해 튜플로 반환합니다. 66 | 67 | ```swift 68 | override func run( 69 | _ observer: Observer, 70 | cancel: Cancelable 71 | ) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element { 72 | let sink = AnonymousObservableSink(observer: observer, cancel: cancel) 73 | let subscription = sink.run(self) 74 | 75 | return (sink: sink, subscription: subscription) 76 | } 77 | ``` 78 | 79 |
80 | 81 | ### [AnonymousObservableSink](https://github.com/ReactiveX/RxSwift/blob/b4307ba0b6425c0ba4178e138799946c3da594f8/RxSwift/Observables/Create.swift#L25) 82 | 83 | - AnonymousObservableSink는 AnonymousObservable로부터 이벤트를 받을 수 있게 하는 객체입니다. 84 | - 내부에 run 메서드를 구현하고 있고, 이 메서드의 인자로 전달되는 AnonymousObservable의 subscribeHandler를 실행시켜 이벤트를 받게됩니다. 85 | 86 | ```swift 87 | func run(_ parent: Parent) -> Disposable { 88 | return parent.subscribeHandler(AnyObserver(self)) 89 | } 90 | ``` 91 | 92 | - AnonymousObservableSink는 메서드는 ObservableType을 채택하고 있기 때문에 자체적인 on 메서드를 구현하고 있습니다. 이 on 메서드는 자신의 부모클래스인 Sink의 forwardOn 메서드를 호출하고 이를 통해 이벤트를 전달합니다. 93 | 94 | ```swift 95 | func on(_ event: Event) { 96 | switch event { 97 | case .next: 98 | self.forwardOn(event: event) 99 | case .error, .completed: 100 | self.forwardOn(event: event) 101 | self.dispose() 102 | } 103 | } 104 | ``` 105 | 106 |
107 | 108 | ### [AnonymousObserver](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Observers/AnonymousObserver.swift) 109 | 110 | - AnonymousObserver는 ObserverBase 타입을 상속합니다. 111 | - AnonymousObserver는 subscribe 내부에서 생성하게되는 Observer입니다. 112 | 113 | ```swift 114 | let observer = AnonymousObserver { event in 115 | switch event { 116 | case .next(let value): 117 | onNext?(value) 118 | case .error(let error): 119 | onError?(error) 120 | disposable.dispose() 121 | case .completed: 122 | onCompleted?() 123 | disposable.dispose() 124 | } 125 | } 126 | ``` 127 | - AnonymousObserver의 생성자에 전달되는 클로저는 내부에 있는 eventHandler 프로퍼티에 할당됩니다. 128 | 129 | ```swift 130 | init(_ eventHandler: @escaping EventHandler) { 131 | self.eventHandler = eventHandler 132 | } 133 | ``` 134 | 135 | - 등록된 이벤트 핸들러는 onCore 메서드를 통해 Event가 전달되면 실행됩니다. 136 | 137 | ```swift 138 | override func onCore(_ event: Event) { 139 | self.eventHandler(event) 140 | } 141 | ``` 142 |
143 | 144 | 145 | ### [AnyObserver](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/AnyObserver.swift) 146 | 147 | - AnyObserver는 ObserverType을 채택합니다. 148 | - AnyObserver는 두 종류의 생성자가 있습니다. 클로저를 받아서 해당 클로저를 이벤트 핸들러인 observer 프로퍼티에 할당하거나, 어떤 ObserverType을 받아 구현된 on 메서드는 observer 프로퍼티에 할당합니다. 149 | 150 | ```swift 151 | public init(eventHandler: @escaping EventHandler) { 152 | self.observer = eventHandler 153 | } 154 | 155 | public init(_ observer: Observer) where Observer.Element == Element { 156 | self.observer = observer.on 157 | } 158 | ``` 159 | - AnyObserver도 ObserverType을 채택하고 있기 때문에 on 메서드를 구현합니다. AnyObserver에서는 on 메서드를 이벤트 핸들러를 호출하고 인자로 전달받은 이벤트를 넘기고 있습니다. 160 | 161 | ```swift 162 | public func on(_ event: Event) { 163 | self.observer(event) 164 | } 165 | ``` 166 | 167 |
168 | 169 | ### [Cancelable](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Cancelable.swift) 170 | 171 | - Cancelable은 Disposable을 채택합니다. 172 | - Cancelable은 객체가 dispose 되었는지 확인할 수 있는 isDisposed 프로퍼티를 정의합니다. 본 프로젝트에서는 isDisposed를 구현하고 있지 않습니다. 173 | 174 | ```swift 175 | public protocol Cancelable : Disposable { 176 | var isDisposed: Bool { get } 177 | } 178 | ``` 179 | 180 |
181 | 182 | ### [Disposables](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Disposables/Disposables.swift) 183 | 184 | - Disposables는 아무것도 가지고 있지 않은 구조체입니다. 185 | 186 | ```swift 187 | struct Disposables {} 188 | ``` 189 | 190 | - Disposables의 Extension에서는 오버로딩으로 세부 타입들이 타입메서드인 create를 호출하면서 세부 타입의 Disposable 인스턴스를 생성하도록 합니다. 본 프로젝트에서는 DefaultDisposables과 BinaryDisposables를 정의하고 있습니다. 191 | 192 | ```swift 193 | extension Disposables { 194 | static public func create() -> Disposable { 195 | return DefaultDisposable() 196 | } 197 | } 198 | 199 | extension Disposables { 200 | public static func create(_ disposable1: Disposable, _ disposable2: Disposable) -> Cancelable { 201 | BinaryDisposables(disposable1, disposable2) 202 | } 203 | } 204 | ``` 205 | 206 |
207 | 208 | ### [Disposable](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Disposable.swift) 209 | 210 | - Disposable은 dispose 메서드의 인터페이스를 가지는 프로토콜입니다. 211 | 212 | ```swift 213 | protocol Disposable { 214 | func dispose() 215 | } 216 | ``` 217 | 218 | - 구체적인 Disposable 타입들은 이 프로토콜을 채택해 구독을 취소할 때 취할 동작을 dispose에 구현합니다. 219 | 220 | ```swift 221 | class DefaultDisposable: Disposable { 222 | func dispose() { 223 | print("disposed") 224 | } 225 | } 226 | ``` 227 | 228 |
229 | 230 | ### [Event](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Event.swift) 231 | 232 | - Event는 시퀀스에 전달할 이벤트를 정의하는 enum입니다. 233 | - next, error, completed가 정의되어 있고, next는 associatedValue로 제네릭을 받습니다. 234 | 235 | ```swift 236 | enum Event { 237 | case next(Element), error(Swift.Error), completed 238 | } 239 | ``` 240 | 241 |
242 | 243 | ### [Observable](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Observable.swift) 244 | 245 | - Observable은 ObservableType을 채택하는 클래스입니다. 246 | - subscribe의 추상 메서드를 가지고 있어 이 클래스를 상속하는 Observable의 구체 타입들이 subscribe를 반드시 구현하도록 합니다. 247 | 248 | ```swift 249 | func subscribe(_ observer: Observer) -> Disposable where Observer.Element == Element { 250 | fatalError() 251 | } 252 | ``` 253 | 254 |
255 | 256 | ### [ObservableConvertibleType](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/ObservableConvertibleType.swift) 257 | 258 | - ObservableConvertibleType은 asObservable 메서드의 인터페이스를 가지는 프로토콜입니다. 259 | 260 | ```swift 261 | protocol ObservableConvertibleType { 262 | associatedtype Element 263 | func asObservable() -> Observable 264 | } 265 | ``` 266 | 267 |
268 | 269 | ### [ObservableType](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/ObservableType.swift) 270 | 271 | - ObservableType은 ObservableConvertibleType을 채택하는 프로토콜입니다. 272 | - 프로토콜에는 subscribe 메서드에 대한 인터페이스가 정의되어 있습니다. 273 | 274 | ```swift 275 | protocol ObservableType: ObservableConvertibleType { 276 | associatedtype Element 277 | func subscribe(_ observer: Observer) -> Disposable where Observer.Element == Element 278 | } 279 | ``` 280 | - ObservableType은 extension으로 create 타입 메서드를 구현하고 있습니다. 이 메서드는 클로저를 인자로 받아 AnonymousObservable을 생성해 반환합니다. 281 | 282 | ```swift 283 | extension ObservableType { 284 | public static func create(_ subscribe: @escaping (AnyObserver) -> Disposable) -> Observable { 285 | return AnonymousObservable(subscribe) 286 | } 287 | } 288 | ``` 289 | 290 | - 또 다른 ObservableType의 extension은 subscribe 메서드를 구현하고 있습니다. 일반적으로 onNext, onError, onCompleted, onDisposed에 전달하는 클로저가 이 메서드에서 AnonymousObserver로 래핑되어 사용됩니다. 291 | 292 | ```swift 293 | extension ObservableType { 294 | func subscribe( 295 | onNext: ((Element) -> Void)? = nil, 296 | onError: ((Swift.Error) -> Void)? = nil, 297 | onCompleted: (() -> Void)? = nil, 298 | onDisposed: (() -> Void)? = nil 299 | ) -> Disposable { 300 | let disposable: Disposable 301 | let observer = AnonymousObserver { event in 302 | switch event { 303 | case .next(let value): 304 | onNext?(value) 305 | case .error(let error): 306 | onError?(error) 307 | disposable.dispose() 308 | case .completed: 309 | onCompleted?() 310 | disposable.dispose() 311 | } 312 | } 313 | return Disposables.create( 314 | self.asObservable().subscribe(observer), 315 | disposable 316 | ) 317 | } 318 | } 319 | ``` 320 | 321 | - 또 다른 ObservableType의 Extension은 ObservableType이 채택하는 ObservableConvertibleType에 있는 asObservable 메서드를 구현합니다. 이 메서드는 자기자신에 대해 subscribe를 부르는 observable를 생성합니다. 322 | 323 | ```swift 324 | func asObservable() -> Observable { 325 | Observable.create { observer in self.subscribe(observer) } 326 | } 327 | ``` 328 | 329 |
330 | 331 | ### [ObserverType](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/ObserverType.swift) 332 | 333 | - ObserverType은 on 메서드를 인터페이스로 가지는 프로토콜입니다. 모든 구체적인 Observer 타입들은 이 프로토콜을 채택하고 on을 구현합니다. 334 | 335 | ```swift 336 | protocol ObserverType { 337 | associatedtype Element 338 | func on(_ event: Event) 339 | } 340 | ``` 341 | 342 | - ObserverType은 Extension에 이벤트에 대한 on 을 좀 더 쉽게 사용할 수 있는 신태틱 슈가를 제공합니다. on(.next)를 onNext()로 간단하게 호출할 수 있게 해줍니다. 343 | 344 | ```swift 345 | extension ObserverType { 346 | public func onNext(_ element: Element) { 347 | self.on(.next(element)) 348 | } 349 | 350 | public func onCompleted() { 351 | self.on(.completed) 352 | } 353 | 354 | public func onError(_ error: Swift.Error) { 355 | self.on(.error(error)) 356 | } 357 | } 358 | ``` 359 | 360 |
361 | 362 | ### [Producer](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Observables/Producer.swift) 363 | 364 | - Producer는 Observable을 상속하는 클래스입니다. 365 | - Observable의 추상 메서드였던 subsribe를 구현하기 때문에 Observable을 subscribe하면 실제로 불리는 메서드는 Producer의 subscribe 메서드가 됩니다. 366 | - subscribe 안에서는 SinkDisposer의 인스턴스를 만들고, sink와 subscription을 생성한 뒤, SinkDisposer에 넣어주고 SinkDisposer 인스턴스를 반환합니다. 367 | 368 | ```swift 369 | override func subscribe(_ observer: Observer) -> Disposable where Observer.Element == Element { 370 | let disposer = SinkDisposer() 371 | let sinkAndSubsription = self.run(observer, cancel: disposer) 372 | 373 | disposer.setSinkAndSubscription(sink: sinkAndSubsription.sink, subscription: sinkAndSubsription.subscription) 374 | return disposer 375 | } 376 | ``` 377 | 378 | - sink는 이벤트가 들어왔을 때 옵저버에게 전달해주는 Disposable이고, subscription은 옵저버에 대해 옵저버블의 subscribeHandler를 실행하는 Disposable입니다. 379 | - sink와 subscription을 만드는 run 메서드는 Observable의 구체 타입에 정의됩니다. 본 프로젝트는 AnonymousObservable만 사용하고 있습니다. 380 | 381 | ```swift 382 | override func run( 383 | _ observer: Observer, 384 | cancel: Cancelable 385 | ) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element { 386 | 387 | let sink = AnonymousObservableSink(observer: observer, cancel: cancel) 388 | let subscription = sink.run(self) 389 | 390 | return (sink: sink, subscription: subscription) 391 | } 392 | ``` 393 | 394 | - AnonymousObservable의 run은, AnonymousObservableSink 인스턴스를 만들고, run 메서드를 실행해 subscription에 반환값을 할당합니다. 395 | 396 |
397 | 398 | ### [Sink](https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/Observables/Sink.swift) 399 | 400 | - Sink는 Disposable을 채택하는 클래스입니다. 401 | - Sink는 ObserverType의 observer 프로퍼티와 Cancelable 타입의 cancel 프로퍼티를 가지고 있습니다. 402 | 403 | ```swift 404 | fileprivate let observer: Observer 405 | fileprivate let cancel: Cancelable 406 | ``` 407 | 408 | - Sink로 이벤트가 전달되면 forwardOn 메서드를 통해 observer에게 이벤트를 전달하고, dispose가 실행되면 cacel의 dispose 메서드를 호출합니다. 409 | 410 | ```swift 411 | func forwardOn(event: Event) { 412 | self.observer.on(event) 413 | } 414 | 415 | func dispose() { 416 | self.cancel.dispose() 417 | } 418 | ``` 419 | 420 |
421 | 422 | ### [SinkDisposer](https://github.com/ReactiveX/RxSwift/blob/b4307ba0b6425c0ba4178e138799946c3da594f8/RxSwift/Observables/Producer.swift#L39) 423 | 424 | - SinkDisposer는 Cancelable을 채택하고 있는 클래스입니다. 425 | - SinkDisposer는 sink와 subscription 프로퍼티를 가지고 있습니다. 426 | 427 | ```swift 428 | private var sink: Disposable? 429 | private var subscription: Disposable? 430 | ``` 431 | 432 | - 두 프로퍼티는 setSinkAndSubscription 메서드를 통해 채워집니다. 이 메서든 subscribe에서 sink와 subscription을 만든 뒤에 호출됩니다. 433 | 434 | ```swift 435 | func setSinkAndSubscription(sink: Disposable, subscription: Disposable) { 436 | self.sink = sink 437 | self.subscription = subscription 438 | } 439 | ``` 440 | 441 | - dispose가 호출되면 sink와 subscription의 dispose를 모두 호출합니다. 442 | 443 | ```swift 444 | func dispose() { 445 | self.sink?.dispose() 446 | self.subscription?.dispose() 447 | self.sink = nil 448 | self.subscription = nil 449 | } 450 | ``` 451 | 452 | - SinkDisposer는 Producer의 subscribe 메서드의 반환 값이기 때문에 subscribe를 통해 얻게되는 Disposable은 사실 SinkDisposer의 인스턴스입니다. 453 | 454 |
455 | 456 | ## 이해하고자 하는 동작들 457 | 458 | ### Observable.create를 하면 일어나는 일 459 | 460 | 461 | [블로그 포스팅 - [RxSwift] Observable.create의 동작원리 이해하기](https://jeonyeohun.tistory.com/374) 462 | 463 | ### observable.subscribe를 하면 일어나는 일 464 | 465 | [블로그 포스팅 - [RxSwift] subscribe의 동작원리 이해하기](https://jeonyeohun.tistory.com/375) 466 | -------------------------------------------------------------------------------- /SimpleReactiveSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B0D0FD6A279A7D7A00195EE5 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD69279A7D7A00195EE5 /* main.swift */; }; 11 | B0D0FD71279A7DB300195EE5 /* ObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD70279A7DB300195EE5 /* ObservableType.swift */; }; 12 | B0D0FD73279A946800195EE5 /* ObservableConvertibleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD72279A946800195EE5 /* ObservableConvertibleType.swift */; }; 13 | B0D0FD75279A947C00195EE5 /* ObserverType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD74279A947C00195EE5 /* ObserverType.swift */; }; 14 | B0D0FD77279A94CC00195EE5 /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD76279A94CC00195EE5 /* AnyObserver.swift */; }; 15 | B0D0FD79279A94EA00195EE5 /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD78279A94EA00195EE5 /* Producer.swift */; }; 16 | B0D0FD7B279A950000195EE5 /* SinkDisposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD7A279A950000195EE5 /* SinkDisposer.swift */; }; 17 | B0D0FD7D279A951000195EE5 /* Disposables.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD7C279A951000195EE5 /* Disposables.swift */; }; 18 | B0D0FD7F279A959000195EE5 /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD7E279A959000195EE5 /* Sink.swift */; }; 19 | B0D0FD81279A95AB00195EE5 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD80279A95AB00195EE5 /* Observable.swift */; }; 20 | B0D0FD83279A95E400195EE5 /* AnonymousObservableSink.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD82279A95E400195EE5 /* AnonymousObservableSink.swift */; }; 21 | B0D0FD85279A960200195EE5 /* AnonymousObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD84279A960200195EE5 /* AnonymousObservable.swift */; }; 22 | B0D0FD87279A961500195EE5 /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD86279A961500195EE5 /* Cancelable.swift */; }; 23 | B0D0FD89279A962D00195EE5 /* AnonymousObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD88279A962D00195EE5 /* AnonymousObserver.swift */; }; 24 | B0D0FD8B279A966D00195EE5 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0D0FD8A279A966D00195EE5 /* Event.swift */; }; 25 | B0FA555C279B1EB90062E712 /* ObserverBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0FA555B279B1EB90062E712 /* ObserverBase.swift */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXCopyFilesBuildPhase section */ 29 | B0D0FD64279A7D7A00195EE5 /* CopyFiles */ = { 30 | isa = PBXCopyFilesBuildPhase; 31 | buildActionMask = 2147483647; 32 | dstPath = /usr/share/man/man1/; 33 | dstSubfolderSpec = 0; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 1; 37 | }; 38 | /* End PBXCopyFilesBuildPhase section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | B0D0FD66279A7D7A00195EE5 /* SimpleReactiveSwift */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SimpleReactiveSwift; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | B0D0FD69279A7D7A00195EE5 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 43 | B0D0FD70279A7DB300195EE5 /* ObservableType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableType.swift; sourceTree = ""; }; 44 | B0D0FD72279A946800195EE5 /* ObservableConvertibleType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableConvertibleType.swift; sourceTree = ""; }; 45 | B0D0FD74279A947C00195EE5 /* ObserverType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObserverType.swift; sourceTree = ""; }; 46 | B0D0FD76279A94CC00195EE5 /* AnyObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyObserver.swift; sourceTree = ""; }; 47 | B0D0FD78279A94EA00195EE5 /* Producer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Producer.swift; sourceTree = ""; }; 48 | B0D0FD7A279A950000195EE5 /* SinkDisposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SinkDisposer.swift; sourceTree = ""; }; 49 | B0D0FD7C279A951000195EE5 /* Disposables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Disposables.swift; sourceTree = ""; }; 50 | B0D0FD7E279A959000195EE5 /* Sink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sink.swift; sourceTree = ""; }; 51 | B0D0FD80279A95AB00195EE5 /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; 52 | B0D0FD82279A95E400195EE5 /* AnonymousObservableSink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnonymousObservableSink.swift; sourceTree = ""; }; 53 | B0D0FD84279A960200195EE5 /* AnonymousObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnonymousObservable.swift; sourceTree = ""; }; 54 | B0D0FD86279A961500195EE5 /* Cancelable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cancelable.swift; sourceTree = ""; }; 55 | B0D0FD88279A962D00195EE5 /* AnonymousObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnonymousObserver.swift; sourceTree = ""; }; 56 | B0D0FD8A279A966D00195EE5 /* Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; 57 | B0FA555B279B1EB90062E712 /* ObserverBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObserverBase.swift; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | B0D0FD63279A7D7A00195EE5 /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | B0D0FD5D279A7D7A00195EE5 = { 72 | isa = PBXGroup; 73 | children = ( 74 | B0D0FD68279A7D7A00195EE5 /* SimpleReactiveSwift */, 75 | B0D0FD67279A7D7A00195EE5 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | B0D0FD67279A7D7A00195EE5 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | B0D0FD66279A7D7A00195EE5 /* SimpleReactiveSwift */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | B0D0FD68279A7D7A00195EE5 /* SimpleReactiveSwift */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | B0D0FD69279A7D7A00195EE5 /* main.swift */, 91 | B0D0FD84279A960200195EE5 /* AnonymousObservable.swift */, 92 | B0D0FD82279A95E400195EE5 /* AnonymousObservableSink.swift */, 93 | B0D0FD88279A962D00195EE5 /* AnonymousObserver.swift */, 94 | B0D0FD76279A94CC00195EE5 /* AnyObserver.swift */, 95 | B0D0FD86279A961500195EE5 /* Cancelable.swift */, 96 | B0D0FD7C279A951000195EE5 /* Disposables.swift */, 97 | B0D0FD8A279A966D00195EE5 /* Event.swift */, 98 | B0D0FD80279A95AB00195EE5 /* Observable.swift */, 99 | B0D0FD72279A946800195EE5 /* ObservableConvertibleType.swift */, 100 | B0D0FD70279A7DB300195EE5 /* ObservableType.swift */, 101 | B0D0FD74279A947C00195EE5 /* ObserverType.swift */, 102 | B0D0FD78279A94EA00195EE5 /* Producer.swift */, 103 | B0D0FD7E279A959000195EE5 /* Sink.swift */, 104 | B0D0FD7A279A950000195EE5 /* SinkDisposer.swift */, 105 | B0FA555B279B1EB90062E712 /* ObserverBase.swift */, 106 | ); 107 | path = SimpleReactiveSwift; 108 | sourceTree = ""; 109 | }; 110 | /* End PBXGroup section */ 111 | 112 | /* Begin PBXNativeTarget section */ 113 | B0D0FD65279A7D7A00195EE5 /* SimpleReactiveSwift */ = { 114 | isa = PBXNativeTarget; 115 | buildConfigurationList = B0D0FD6D279A7D7A00195EE5 /* Build configuration list for PBXNativeTarget "SimpleReactiveSwift" */; 116 | buildPhases = ( 117 | B0D0FD62279A7D7A00195EE5 /* Sources */, 118 | B0D0FD63279A7D7A00195EE5 /* Frameworks */, 119 | B0D0FD64279A7D7A00195EE5 /* CopyFiles */, 120 | ); 121 | buildRules = ( 122 | ); 123 | dependencies = ( 124 | ); 125 | name = SimpleReactiveSwift; 126 | productName = SimpleReactiveSwift; 127 | productReference = B0D0FD66279A7D7A00195EE5 /* SimpleReactiveSwift */; 128 | productType = "com.apple.product-type.tool"; 129 | }; 130 | /* End PBXNativeTarget section */ 131 | 132 | /* Begin PBXProject section */ 133 | B0D0FD5E279A7D7A00195EE5 /* Project object */ = { 134 | isa = PBXProject; 135 | attributes = { 136 | BuildIndependentTargetsInParallel = 1; 137 | LastSwiftUpdateCheck = 1320; 138 | LastUpgradeCheck = 1320; 139 | TargetAttributes = { 140 | B0D0FD65279A7D7A00195EE5 = { 141 | CreatedOnToolsVersion = 13.2.1; 142 | }; 143 | }; 144 | }; 145 | buildConfigurationList = B0D0FD61279A7D7A00195EE5 /* Build configuration list for PBXProject "SimpleReactiveSwift" */; 146 | compatibilityVersion = "Xcode 13.0"; 147 | developmentRegion = en; 148 | hasScannedForEncodings = 0; 149 | knownRegions = ( 150 | en, 151 | Base, 152 | ); 153 | mainGroup = B0D0FD5D279A7D7A00195EE5; 154 | productRefGroup = B0D0FD67279A7D7A00195EE5 /* Products */; 155 | projectDirPath = ""; 156 | projectRoot = ""; 157 | targets = ( 158 | B0D0FD65279A7D7A00195EE5 /* SimpleReactiveSwift */, 159 | ); 160 | }; 161 | /* End PBXProject section */ 162 | 163 | /* Begin PBXSourcesBuildPhase section */ 164 | B0D0FD62279A7D7A00195EE5 /* Sources */ = { 165 | isa = PBXSourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | B0FA555C279B1EB90062E712 /* ObserverBase.swift in Sources */, 169 | B0D0FD73279A946800195EE5 /* ObservableConvertibleType.swift in Sources */, 170 | B0D0FD71279A7DB300195EE5 /* ObservableType.swift in Sources */, 171 | B0D0FD87279A961500195EE5 /* Cancelable.swift in Sources */, 172 | B0D0FD85279A960200195EE5 /* AnonymousObservable.swift in Sources */, 173 | B0D0FD8B279A966D00195EE5 /* Event.swift in Sources */, 174 | B0D0FD7F279A959000195EE5 /* Sink.swift in Sources */, 175 | B0D0FD7B279A950000195EE5 /* SinkDisposer.swift in Sources */, 176 | B0D0FD77279A94CC00195EE5 /* AnyObserver.swift in Sources */, 177 | B0D0FD79279A94EA00195EE5 /* Producer.swift in Sources */, 178 | B0D0FD81279A95AB00195EE5 /* Observable.swift in Sources */, 179 | B0D0FD7D279A951000195EE5 /* Disposables.swift in Sources */, 180 | B0D0FD6A279A7D7A00195EE5 /* main.swift in Sources */, 181 | B0D0FD89279A962D00195EE5 /* AnonymousObserver.swift in Sources */, 182 | B0D0FD75279A947C00195EE5 /* ObserverType.swift in Sources */, 183 | B0D0FD83279A95E400195EE5 /* AnonymousObservableSink.swift in Sources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXSourcesBuildPhase section */ 188 | 189 | /* Begin XCBuildConfiguration section */ 190 | B0D0FD6B279A7D7A00195EE5 /* Debug */ = { 191 | isa = XCBuildConfiguration; 192 | buildSettings = { 193 | ALWAYS_SEARCH_USER_PATHS = NO; 194 | CLANG_ANALYZER_NONNULL = YES; 195 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 196 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 197 | CLANG_CXX_LIBRARY = "libc++"; 198 | CLANG_ENABLE_MODULES = YES; 199 | CLANG_ENABLE_OBJC_ARC = YES; 200 | CLANG_ENABLE_OBJC_WEAK = YES; 201 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 202 | CLANG_WARN_BOOL_CONVERSION = YES; 203 | CLANG_WARN_COMMA = YES; 204 | CLANG_WARN_CONSTANT_CONVERSION = YES; 205 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 206 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 207 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 208 | CLANG_WARN_EMPTY_BODY = YES; 209 | CLANG_WARN_ENUM_CONVERSION = YES; 210 | CLANG_WARN_INFINITE_RECURSION = YES; 211 | CLANG_WARN_INT_CONVERSION = YES; 212 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 213 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 214 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 216 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 217 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 218 | CLANG_WARN_STRICT_PROTOTYPES = YES; 219 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 220 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 221 | CLANG_WARN_UNREACHABLE_CODE = YES; 222 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 223 | COPY_PHASE_STRIP = NO; 224 | DEBUG_INFORMATION_FORMAT = dwarf; 225 | ENABLE_STRICT_OBJC_MSGSEND = YES; 226 | ENABLE_TESTABILITY = YES; 227 | GCC_C_LANGUAGE_STANDARD = gnu11; 228 | GCC_DYNAMIC_NO_PIC = NO; 229 | GCC_NO_COMMON_BLOCKS = YES; 230 | GCC_OPTIMIZATION_LEVEL = 0; 231 | GCC_PREPROCESSOR_DEFINITIONS = ( 232 | "DEBUG=1", 233 | "$(inherited)", 234 | ); 235 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 236 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 237 | GCC_WARN_UNDECLARED_SELECTOR = YES; 238 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 239 | GCC_WARN_UNUSED_FUNCTION = YES; 240 | GCC_WARN_UNUSED_VARIABLE = YES; 241 | MACOSX_DEPLOYMENT_TARGET = 12.0; 242 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 243 | MTL_FAST_MATH = YES; 244 | ONLY_ACTIVE_ARCH = YES; 245 | SDKROOT = macosx; 246 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 247 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 248 | }; 249 | name = Debug; 250 | }; 251 | B0D0FD6C279A7D7A00195EE5 /* Release */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | ALWAYS_SEARCH_USER_PATHS = NO; 255 | CLANG_ANALYZER_NONNULL = YES; 256 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 258 | CLANG_CXX_LIBRARY = "libc++"; 259 | CLANG_ENABLE_MODULES = YES; 260 | CLANG_ENABLE_OBJC_ARC = YES; 261 | CLANG_ENABLE_OBJC_WEAK = YES; 262 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_COMMA = YES; 265 | CLANG_WARN_CONSTANT_CONVERSION = YES; 266 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 267 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 268 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 269 | CLANG_WARN_EMPTY_BODY = YES; 270 | CLANG_WARN_ENUM_CONVERSION = YES; 271 | CLANG_WARN_INFINITE_RECURSION = YES; 272 | CLANG_WARN_INT_CONVERSION = YES; 273 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 274 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 275 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 276 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 277 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 279 | CLANG_WARN_STRICT_PROTOTYPES = YES; 280 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 281 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 282 | CLANG_WARN_UNREACHABLE_CODE = YES; 283 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 284 | COPY_PHASE_STRIP = NO; 285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 286 | ENABLE_NS_ASSERTIONS = NO; 287 | ENABLE_STRICT_OBJC_MSGSEND = YES; 288 | GCC_C_LANGUAGE_STANDARD = gnu11; 289 | GCC_NO_COMMON_BLOCKS = YES; 290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 292 | GCC_WARN_UNDECLARED_SELECTOR = YES; 293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 294 | GCC_WARN_UNUSED_FUNCTION = YES; 295 | GCC_WARN_UNUSED_VARIABLE = YES; 296 | MACOSX_DEPLOYMENT_TARGET = 12.0; 297 | MTL_ENABLE_DEBUG_INFO = NO; 298 | MTL_FAST_MATH = YES; 299 | SDKROOT = macosx; 300 | SWIFT_COMPILATION_MODE = wholemodule; 301 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 302 | }; 303 | name = Release; 304 | }; 305 | B0D0FD6E279A7D7A00195EE5 /* Debug */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | CODE_SIGN_STYLE = Automatic; 309 | DEVELOPMENT_TEAM = CH6R3C4FBD; 310 | ENABLE_HARDENED_RUNTIME = YES; 311 | PRODUCT_NAME = "$(TARGET_NAME)"; 312 | SWIFT_VERSION = 5.0; 313 | }; 314 | name = Debug; 315 | }; 316 | B0D0FD6F279A7D7A00195EE5 /* Release */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | CODE_SIGN_STYLE = Automatic; 320 | DEVELOPMENT_TEAM = CH6R3C4FBD; 321 | ENABLE_HARDENED_RUNTIME = YES; 322 | PRODUCT_NAME = "$(TARGET_NAME)"; 323 | SWIFT_VERSION = 5.0; 324 | }; 325 | name = Release; 326 | }; 327 | /* End XCBuildConfiguration section */ 328 | 329 | /* Begin XCConfigurationList section */ 330 | B0D0FD61279A7D7A00195EE5 /* Build configuration list for PBXProject "SimpleReactiveSwift" */ = { 331 | isa = XCConfigurationList; 332 | buildConfigurations = ( 333 | B0D0FD6B279A7D7A00195EE5 /* Debug */, 334 | B0D0FD6C279A7D7A00195EE5 /* Release */, 335 | ); 336 | defaultConfigurationIsVisible = 0; 337 | defaultConfigurationName = Release; 338 | }; 339 | B0D0FD6D279A7D7A00195EE5 /* Build configuration list for PBXNativeTarget "SimpleReactiveSwift" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | B0D0FD6E279A7D7A00195EE5 /* Debug */, 343 | B0D0FD6F279A7D7A00195EE5 /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | /* End XCConfigurationList section */ 349 | }; 350 | rootObject = B0D0FD5E279A7D7A00195EE5 /* Project object */; 351 | } 352 | -------------------------------------------------------------------------------- /SimpleReactiveSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SimpleReactiveSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SimpleReactiveSwift.xcodeproj/project.xcworkspace/xcuserdata/jeonyeohun.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeonyeohun/Understanding-RxSwift-Internals/71fccd5c2a106faba746a6a393d179a2cdaaab95/SimpleReactiveSwift.xcodeproj/project.xcworkspace/xcuserdata/jeonyeohun.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SimpleReactiveSwift.xcodeproj/xcuserdata/jeonyeohun.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SimpleReactiveSwift.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/AnonymousObservable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnonymousObservable.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class AnonymousObservable: Producer { 11 | typealias SubscribeHandler = (AnyObserver) -> Disposable 12 | 13 | let subscribeHandler: SubscribeHandler 14 | 15 | /* 여행 3 */ 16 | // 아까 만들었던 두 개의 정수를 next로 방출하고 completed를 방출하는 클로저가 생성자에 전달된다. 17 | // 그리고 생성자에서는 subscribeHandler에 클로저를 저장하고 끝이다. 18 | // 이름만 보고 유추해보면 그 클로저를 구독자가 발생하면 실행하는 것 같다. 19 | // 일단 create를 통해 알 수 있는 정보는 이게 다인 것 같다. 다시 main으로 돌아가자. 20 | init(_ subscribeHandler: @escaping SubscribeHandler) { 21 | self.subscribeHandler = subscribeHandler 22 | } 23 | 24 | /* 여행 10 */ 25 | // run으로 왔다. 여기에 전달되는 인자는 observer와 cancelable이다. 26 | override func run( 27 | _ observer: Observer, 28 | cancel: Cancelable 29 | ) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element { 30 | // 가장 먼저 하는건 AnonymousObservableSink를 만드는 것이다. 이게 뭐람.. 31 | // 들어가보자. Jump to definition. 32 | 33 | // 결국엔 AnonymousObservableSink 인스턴스를 만드는 것 외에는 따로 하는게 없고, 이 인스턴스는 생성자에서 자신의 부모 클래스인 Sink에게 observer와 cancel을 전달한다. 34 | let sink = AnonymousObservableSink(observer: observer, cancel: cancel) 35 | 36 | // subscription은 위에서 만든 AnonymousObservableSink의 run 메서드를 통해 만들어진다. 그리고 인자로는 self를 전달한다. 37 | // 여기서 self는 AnonymousObservable이다. self.asObservable().subscribe(observer) 여기서 asObservable()에서 반환된 그 녀석이 맞다. 38 | // sink.run으로 이동해보자. Jump to definition 39 | 40 | /* 여행 17 */ 41 | // -- 이번 self는 또 다르다. { observer in self.subscribe(observer) } 여기에서 self와 같다. self.subscirbe로 producer가 불렸으니까 당연한 이야기다. run을 실행하자. 42 | let subscription = sink.run(self) 43 | 44 | return (sink: sink, subscription: subscription) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/AnonymousObservableSink.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnonymousObservableSink.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class AnonymousObservableSink: Sink, ObserverType { 11 | typealias Element = Observer.Element 12 | typealias Parent = AnonymousObservable 13 | 14 | /* 여행 11 */ 15 | // 생성자를 보니 상위 타입의 생성자를 부르고 있다. 16 | // 상위 타입은 Sink이니까 저기로 가봐야할 것 같다. 고고 Jump to definition. 17 | override init(observer: Observer, cancel: Cancelable) { 18 | super.init(observer: observer, cancel: cancel) 19 | } 20 | 21 | /* 여행 15 */ 22 | // on 메서드는 .next 에 대해서는 forwadOn만 부르면서 이벤트를 전달하고, error나 completed는 forwardOn을 부른뒤에 dispose하고있다. 23 | // 이 함수를 통채로 AnyObserver의 observer 프로퍼티에 등록하는 것이다. 24 | // forwardOn은 여기에 없으니 상위 타입인 Sink에 있겠지. 이제 뭔가 퍼즐이 맞춰진다. 근데 아직 on이 호출된 것은 아니니까 일단 돌아가자. 25 | func on(_ event: Event) { 26 | switch event { 27 | case .next: 28 | /* 여행 22 */ 29 | // forwardOn으로 이벤트가 전달된다. 30 | self.forwardOn(event: event) 31 | case .error, .completed: 32 | self.forwardOn(event: event) 33 | self.dispose() 34 | } 35 | } 36 | 37 | func run(_ parent: Parent) -> Disposable { 38 | /* 여행 13 */ 39 | // run의 인자로 전달된 parent는 AnonymousObservable이다. 지금까지 따라오느라 헷갈릴 것 같아 정리하면 이 AnonymousObservable은 첫 subscribe 가장 마지막에서 Disposables.create안에 들어가는 첫번째 인자에서 만들어진 AnonymousObservable이다. 40 | // 그때 우리는 self.asObservable().create(observer) 라는 코드를 봤었는데, 자기자신에 대한 AnonymousObservable을 asObservable을 통해 만들었었다. 41 | // 그리고 이 인스턴스 안에는 { observer in self.subscribe(observer) } 이 클로저가 subscribeHandler로 들어가 있다. 이해가 안된다면 asObservable이 어떻게 구현되어 있는지 보면된다. 42 | // 그럼 아래에서는 결국에는 { observer in self.subscribe(observer) } 이 클로저를 실행하는 것과 같다. 그리고 인자로 self를 AnyObserver로 형변환하게 된다. 43 | // 여기서 self는 AnonymousObservableSink이고, 상위 타입인 Sink에 이벤트 처리 클로저인 eventHandler를 가진 observer 프로퍼티와 아까 만들었던 SinkDisposer의 인스턴스인 cancel이 들어가 있다. 44 | // 그럼 형 변환을 하면 어떻게 되는지 AnyObserver의 생성자부터 보자. Jump to definition. 45 | 46 | // 다시 돌아왔다. AnyObserver의 observer 프로퍼티에는 self에 들어있던 forwadOn을 호출하는 클로저가 들어간다. 47 | // 이제 subscribeHandler를 실행할 차례다. 48 | // { observer in self.subscribe(observer) } 이 클로저의 인자로 AnyObserver가 들어가게되고, subscribe를 해주니 subsribe가 한 번 더 호출된다. 다시 producer로 가보자. 49 | 50 | /* 여행 18 */ 51 | // -- 다시 run으로 돌아왔다. 이번에 parent는 { observer in self.subscribe(observer) } 이 클로저에서 캡쳐된 self이고, self의 subscriptionHandler는 create에서 만들었던 이벤트를 방출했던 클로저이다. 52 | // -- 따라서 이제 그 클로저에 현재 self, 즉 이전 방문에서 만든 AnyObserver의 EventHandler가 AnyObserver로 전달된다. 53 | // -- 그럼 이제 create 에서 만든 클로저를 실행하러 main으로 가자 54 | return parent.subscribeHandler(AnyObserver(self)) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/AnonymousObserver.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnonymousObserver.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | final class AnonymousObserver: ObserverBase { 11 | typealias EventHandler = (Event) -> Void 12 | 13 | private let eventHandler : EventHandler 14 | /* 여행 5 */ 15 | // AnonymousObserver는 만들어지면서 전달된 클로저를 EventHandler로 등록한다. 16 | // 이 말은 곧 subsribe를 하면서 만들었던 이벤트별 클로저들이 switch로 감싸진 하나의 클로저가 되어서 이곳에 등록되는 것이다. 17 | // 왜 eventHandler인지 납득이 된다. 이제 다시 돌아가자. 18 | init(_ eventHandler: @escaping EventHandler) { 19 | self.eventHandler = eventHandler 20 | } 21 | 22 | override func onCore(_ event: Event) { 23 | /* 여행 25 */ 24 | // 마침내 이벤트가 이벤트 핸들러에 도착했다. 위에 적혀있는대로, subscribe를 하면서 만들어진 switch 클로저에 이벤트가 인자로 전달된다. 25 | self.eventHandler(event) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/AnyObserver.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyObserver.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | struct AnyObserver: ObserverType { 11 | public typealias EventHandler = (Event) -> Void 12 | 13 | private let observer: EventHandler 14 | 15 | public init(eventHandler: @escaping EventHandler) { 16 | self.observer = eventHandler 17 | } 18 | 19 | /* 여행 14 */ 20 | // 이 생성자가 하는 일은 간단하다. 자신의 인자로 전달된 Observer의 on 메서드를 자신의 eventHandler로 잡아주는 것이다. 21 | // on 메서드를 그럼 보고와야겠다. 여기서 인자로 전달된 인스턴스의 타입은 AnonymousObservableSink 이니까 그 안에 들어있는 on 메서드를 확인해보자. 22 | // 이번에는 jump to definition이 안되니까 찾아가자.. 23 | 24 | // 결국 이벤트를 받아서 forwardOn으로 보내거나 추가적으로 dispose까지 실행해주는 클로저가 AnyObserver의 observer 프로퍼티에 담긴다. 25 | // 다시 돌아가자. 26 | public init(_ observer: Observer) where Observer.Element == Element { 27 | self.observer = observer.on 28 | } 29 | 30 | public func on(_ event: Event) { 31 | /* 여행 21 */ 32 | // on에 도착했다. 여기서 하는 일은 전달받은 이벤트를 observer에 인자로 전달하는 것이다. 33 | // AnyOnserver의 observer에는 아까 만든 AnonymousObservableSink의 on 메서드가 들어있다. 34 | // forwardOn으로 이벤트를 전달하고 있었으니까, 다시 그 메서드를 보고오자. 35 | self.observer(event) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/Cancelable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Cancelable.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | protocol Cancelable: Disposable {} 12 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/Disposables.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Disposables.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Disposables {} 11 | 12 | extension Disposables { 13 | static public func create() -> Disposable { 14 | return DefaultDisposable() 15 | } 16 | } 17 | 18 | protocol Disposable { 19 | func dispose() 20 | } 21 | 22 | class DefaultDisposable: Disposable { 23 | func dispose() { 24 | print("disposed") 25 | } 26 | } 27 | 28 | // 단순하다. 그냥 두 개의 Disposable을 저장해두고, dispose가 불리면 두 disposable의 dispose를 각각 불러준 뒤에 인스턴스를 해제한다. 29 | // 그럼 두 개 주는건 이해됐으니까 다시 ObservableType.swift로 돌아가자. 30 | class BinaryDisposables: Cancelable { 31 | private var disposable1: Disposable? 32 | private var disposable2: Disposable? 33 | 34 | init(_ disposable1: Disposable, _ disposable2: Disposable) { 35 | self.disposable1 = disposable1 36 | self.disposable2 = disposable2 37 | } 38 | 39 | func dispose() { 40 | self.disposable1?.dispose() 41 | self.disposable2?.dispose() 42 | self.disposable1 = nil 43 | self.disposable2 = nil 44 | } 45 | } 46 | 47 | /* 여행 6 */ 48 | // Disposables의 extension이 있고 여기서느 두개의 Disposable을 받아 BinaryDisposables를 만든다. 49 | // BinaryDisposable은 위에 있으니까 올려서 어떤 녀식인지 확인해보자. 50 | extension Disposables { 51 | public static func create(_ disposable1: Disposable, _ disposable2: Disposable) -> Cancelable { 52 | BinaryDisposables(disposable1, disposable2) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/Event.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Event.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | enum Event { 11 | case next(Element), error(Swift.Error), completed 12 | } 13 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/Observable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Observable.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class Observable: ObservableType { 11 | typealias Element = Element 12 | func subscribe(_ observer: Observer) -> Disposable where Observer.Element == Element { 13 | fatalError() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/ObservableConvertibleType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObservableConvertibleType.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol ObservableConvertibleType { 11 | associatedtype Element 12 | func asObservable() -> Observable 13 | } 14 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/ObservableType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObservableType.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol ObservableType: ObservableConvertibleType { 11 | associatedtype Element 12 | func subscribe(_ observer: Observer) -> Disposable where Observer.Element == Element 13 | } 14 | 15 | extension ObservableType { 16 | /* 여행 2 */ 17 | // 일단 들어왔는데, Observable이 아니다. 우리는 Observable.create를 불렀는데? 18 | // 그렇다. create는 Observable이 채택하는 프로토콜인 ObservableType에 정의되어 있다. 19 | // 심지어 subscribe도 ObservableType이 인터페이스를 들고 있는데, 이건 좀 있다가 알아보자. 20 | // create 메서드에서 하는 일은 단순하다. AnonymousObservable 인스턴스를 만들고 반환한다. 21 | // 그리고 생성자에 우리가 create를 부르면서 정의했던 클로저가 전달된다. 22 | // -> 이 클로저는 23 | // { observer in 24 | // observer.onNext(1) 25 | // observer.onNext(2) 26 | // observer.onCompleted() 27 | // return Disposables.create() 28 | // } 29 | // 이 녀석이다. 30 | // 이제 AnonymousObservable이 뭔지 알아야겠지? Jump to Definition. 31 | public static func create(_ subscribe: @escaping (AnyObserver) -> Disposable) -> Observable { 32 | return AnonymousObservable(subscribe) 33 | } 34 | } 35 | 36 | extension ObservableType { 37 | /* 여행 4 */ 38 | // subscribe 메서드의 구현체로 도착했다. 인자로 받는 클로저들이 nil을 디폴트로 가진다. 아 이래서 아무 클로저를 만들지 않아도, onNext만 만들어도 문제가 없었던 것이었다. 39 | // subscribe는 disposable을 반환한다. 이건 당연하다.. 구독을 취속하려면 취소할 수 있게 해주는 인스턴스를 줘야하니까. 40 | // 구현을 구체적으로 보기 위해서 아래로 내려가자. 41 | func subscribe( 42 | onNext: ((Element) -> Void)? = nil, 43 | onError: ((Swift.Error) -> Void)? = nil, 44 | onCompleted: (() -> Void)? = nil, 45 | onDisposed: (() -> Void)? = nil 46 | ) -> Disposable { 47 | let disposable: Disposable 48 | 49 | // 일단 여기에서 disposable을 하나 만든다. 나는 구독 취소시 동작을 지정할 수 없도록 만들어서 그냥 빈 disposable을 만든다. 50 | disposable = Disposables.create() 51 | 52 | // 갑자기 AnonymousObserver를 만든다. 53 | // 이 옵저버가 하는 일은 어떤 이벤트가 들어왔을 때 subscribe의 인자로 들어온 이벤트에 맞는 메서드들을 실행하는 것이다. 54 | // 그렇다. subscribe 자체가 구독자가 아니라, 내부에서 구독자를 만들고 있었던 것이다. 55 | // 어떻게 만들어지는지 잠시 보고오자. Jump to definition. 56 | // 간단하다. 결국은 switch문으로 이벤트에 대한 동작을 전달받을 클로저로 정의하고, 이 과정을 eventHandler에 등록해주는 것이다. 57 | let observer = AnonymousObserver { event in 58 | switch event { 59 | /* 여행 27 */ 60 | // 돌고돌아 다시 여기까지 왔다. 61 | // 이벤트가 이 클로저에 전달되고 onNext가 불리면서 사전에 정의한 next에 대한 클로저가 실행된다. 62 | case .next(let value): 63 | onNext?(value) 64 | case .error(let error): 65 | onError?(error) 66 | disposable.dispose() // 우리가 알고있는대로 에러나 컴플리션 이벤트가 발생하면 dispose 메서드가 호출된다. 67 | case .completed: 68 | onCompleted?() 69 | disposable.dispose() 70 | } 71 | } 72 | return Disposables.create( // 마지막에 disposable을 만든다. 근데 안에 전달되는 인자가 두 개다. 뭐지? 인자를 두 개 받는 Dispoables.create를 찾아가보자. 아직 이 메서드가 안끝났으면 여기로 다시 돌아와야한다. 창 끄지 말고 Jump to definition. 73 | self.asObservable().subscribe(observer), 74 | // 다시 돌아왔으니 이걸 먼저보자. 자기자신의 asObservable을 실행하고 subscribe한 결과를 반환한다. 그리고 subscribe의 인자로 위에서 만든 observer를 전달한다. 와우. 무슨말인지 모르겠는걸? 75 | // 일단 self부터 정의하자. self는 내가 subscribe를 불렀던 대상이니까 Observable 이녀석의 인스턴일 것이다. 76 | // 그럼 그 인스턴스의 asObservable을 먼저 봐야겠으니까 또 점프해보자. Jump to definition. 구현체로 찾아가야 하니까 ObservableType안에 들어있는 asObservable로 가면 된다(사실 스크롤 내리면 밑에 있다). 77 | // ======== 78 | // 다시 돌아왔다. 그럼 AnonymousObservable이 반환되었고, 이 인스턴스가 가지고 있는 subscribe메서드를 호출한다. 그리고 인자로 위에서 만들었던 observer를 전달한다. observer의 존재를 잊었을까봐 다시 적어보면, subscribe를 할 때 작성한 각 이벤트에 대한 클로저를 가지고 있는 객체이다. 79 | // 그럼 이제 subscribe를 보면 되겠지? Jump to definition. subscribe의 구현체는 Producer에 있다. 사실 AnonymousObservable은 Producer를 상속하고 있었다. 80 | disposable 81 | ) 82 | } 83 | } 84 | 85 | extension ObservableType { 86 | /* 여행 7 */ 87 | // asObservable이 하는 일은 간단하다. Observable.create를 다시 부른다. 88 | // 그리고 이번에는 create 메서드의 인자로 이벤트를 방출하는 클로저가 아니라 자기자신을 subscribe하는 클로저를 보내고 그 인자로 전달받은 observer를 그대로 전달한다. 89 | // 헷갈리지만 생각해보면 이해된다. 맨처음에 만들었던 Observable가 여전히 타겟이고, 이번에는 이 친구의 subscribe를 호출하는 클로저를 전달하는것이다. 그리고 그 클로저에 observer를 전달하는 것이고. 90 | // 그럼 아까 보았던대로, AnonymousObservable이 하나 만들어질 것이다. 그리고 그 안에 있는 subscribeHandler는 { observer in self.subscribe(observer) } 이게 되겠지. 이때 self는 캡쳐해서 가지고 들어간 것이니까 AnonymousObservable이 아니라 create를 호출한 인스턴스다. 91 | // 정리하자면 subscribeHandler로 self.subscribe(observer)를 등록한 AnonymousObservable이 반환된다. 92 | // 오키 여기는 일단 알겠다. 다시 돌아가자. 93 | func asObservable() -> Observable { 94 | Observable.create { observer in self.subscribe(observer) } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/ObserverBase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObserverBase.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/22. 6 | // 7 | 8 | import Foundation 9 | 10 | class ObserverBase : Disposable, ObserverType { 11 | 12 | func on(_ event: Event) { 13 | switch event { 14 | case .next: 15 | /* 여행 24 */ 16 | // ObserverBase는 onCore를 부르고 있다. 근데 얘는 AnonymousObserver에서 오버라이딩하고 있다. 17 | // 다시 AnonymousObserver로 이동하자. 18 | self.onCore(event) 19 | case .error, .completed: 20 | self.onCore(event) 21 | } 22 | } 23 | 24 | func onCore(_ event: Event) {} 25 | 26 | func dispose() {} 27 | } 28 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/ObserverType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObserverType.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol ObserverType { 11 | associatedtype Element 12 | func on(_ event: Event) 13 | } 14 | 15 | extension ObserverType { 16 | /* 여행 20 */ 17 | // onNext는 ObservableType에서 제공해주는 on(.next(element))의 축약형이었다.. 18 | // 그럼 결국 AnyObserver의 on을 찾아가면된다. 19 | public func onNext(_ element: Element) { 20 | self.on(.next(element)) 21 | } 22 | 23 | public func onCompleted() { 24 | self.on(.completed) 25 | } 26 | 27 | public func onError(_ error: Swift.Error) { 28 | self.on(.error(error)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/Producer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Producer.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class Producer: Observable { 11 | /* 여행 8 */ 12 | // 실제 RxSwift는 이것보다 더 복잡하다. 스레드를 선택하는 분기가 있어서 그렇다. 우리는 핵심만 보기로 했으니까 주요한 로직만 남기고 과감하게 지워주었다. 13 | override func subscribe(_ observer: Observer) -> Disposable where Observer.Element == Element { 14 | /* 여행 16 */ 15 | // -- 다시 Producer의 subscribe로 돌아왔다. 헷갈리지 않기 위해 다시 방문했을 때의 동작은 작대기를 붙여서 표현한다. 16 | 17 | // subscribe가 실행되면 하는 일을 확인해보자. 일단 인자로 전달된 observer 안에는 이벤트 별로 어떻게 처리할지 정의되어 있는 eventHandler가 등록되어 있다는 사실을 계속 기억하자. 18 | 19 | // 제일 먼저 하는 일은 SinkDisposer 인스턴스를 만드는 것이다. 20 | // 일단 모르겠으면 무조건 뭐다? Jump to definition. 21 | let disposer = SinkDisposer() // SinkDisposer가 뭔지 알았다. 그냥 안에 sink랑 subscription이라는 애들이 있는 것이다. 22 | 23 | // sink와 subscription은 여기에서 만든다. 이제는 run 메서드를 확인해보자. 24 | // 인자로 전달되는 객체는 eventHandler를 담은 observer와 방금 만든 비어있는 SinkDisposer 인스턴스이다. 25 | // run메서드는 AnonymousObservable에 정의되어 있다. Jump to definition. 26 | let sinkAndSubsription = self.run(observer, cancel: disposer) 27 | 28 | // -- 이번에도 똑같이 동작하지만 observer가 다르다. 이번 observer는 아까 생성했던 AnyObserver였다. 29 | // -- AnyObserver를 들고 run으로 들어가보자. 30 | 31 | disposer.setSinkAndSubscription(sink: sinkAndSubsription.sink, subscription: sinkAndSubsription.subscription) 32 | return disposer 33 | } 34 | 35 | func run( 36 | _ observer: Observer, 37 | cancel: Cancelable 38 | ) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element { 39 | fatalError() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/Sink.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sink.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class Sink: Disposable { 11 | fileprivate let observer: Observer 12 | fileprivate let cancel: Cancelable 13 | 14 | /* 여행 12 */ 15 | // Sink 에는 두 개의 프로퍼티가 있다. observer와 cancel. 지금까지 계속 인자로 넘기던 그 친구들이다. 16 | // 잊었을까봐 다시 언급하면 observer는 이벤트 처리 클로저를 담은 eventHandler를 가지고 있는 AnonymousObserver 객체이고, cancel은 아직은 비어있는 sink와 subscription을 가진 SinkDisposer 객체이다. 17 | // 그럼 정리해보면 subscribe 가장 처음 호출하면서 만들었던 AnonymousObserver와 SinkDisposer 인스턴스이다. 18 | init(observer: Observer, cancel: Cancelable) { 19 | self.observer = observer 20 | self.cancel = cancel 21 | } 22 | 23 | /* 여행 16 */ 24 | // forwardOn이 하는 일은 단순하다. 이벤트를 받아서, 등록된 옵저버에게 건네주면 끝이다. 25 | // 여기에 등록된 옵저버는 아까 계속 잊지말자고 했던 subscribe를 호출하면서 만들었던 AnonymousObserver, 즉, main에서 정의한 이벤트 처리 로직을 들고있는 인스턴스이다. 26 | // 27 | func forwardOn(event: Event) { 28 | /* 여행 23 */ 29 | // 최종적으로 Sink가 가지고 있던 observer의 on 메서드가 호출된다. 30 | // 지금 Sink가 가지고 있는 Observer의 타입은 AnonymousObserver이다. 따라서 AnonymousObserver의 on을 찾아가자. 31 | // 그런데 AnonymousObserver에는 on의 구현이 없다. 상위 클래스인 ObserverBase로 찾아가야한다. 32 | self.observer.on(event) 33 | } 34 | 35 | func dispose() { 36 | self.cancel.dispose() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/SinkDisposer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SinkDisposer.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | /* 여행 9 */ 11 | // SinkDisposer에 도착했다. 내부에 어떻게 되어있는지 확인해보자. 12 | class SinkDisposer: Cancelable { 13 | // SinkDisposer는 두 개의 프로퍼티를 가지고 있다. sink와 subscription. 14 | private var sink: Disposable? 15 | private var subscription: Disposable? 16 | 17 | // 그리고 이 메서드가 실행되면 두 프로퍼티를 채워주고, 18 | func setSinkAndSubscription(sink: Disposable, subscription: Disposable) { 19 | self.sink = sink 20 | self.subscription = subscription 21 | } 22 | 23 | // dispose가 실행되면 sink와 subscription을 모두 dispose한다. 24 | // 일단 인스턴스를 만들기만 했으니까 다시 돌아가자. sink와 subscription이 내부에 있고 둘 다 Disposable 타입이라는 것을 기억하면 될 것 같다. 25 | func dispose() { 26 | self.sink?.dispose() 27 | self.subscription?.dispose() 28 | self.sink = nil 29 | self.subscription = nil 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SimpleReactiveSwift/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // SimpleReactiveSwift 4 | // 5 | // Created by 전여훈 on 2022/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | /* 여행 1 */ 11 | // create에 들어가는 클로저의 타입은 (AnyObserver) -> Disposable) -> Observable. 12 | // observer 혹은 emitter로 써오던 파라미터가 결국 AnyObserver였음을 알 수 있다. AnyObserver에 onNext나 onComplete 같은 이벤트를 방출해주는 것 13 | // create의 반환 타입은 Observable. 즉, create는 말 그대로 observable을 만드는 메서드이고, 만들 때 내부에 방출할 이벤트를 전달해준다. 14 | // 전달되는 클로저의 반환타입은 disposable이다. 그래서 Disposables.create를 호출해준다. create에 클로저가 전달되면 dispose가 호출되었을 때 그 클로저를 실행한다. 15 | // 그럼 create 메서드를 더 자세히 보자. Observable.create가 있는 곳으로 이동하자. create에 우클릭하고 jump to definition 고고 16 | let observable = Observable.create { observer in 17 | 18 | /* 여행 19 */ 19 | // 클로저에 왔다. 이곳에 전달된 observer는 AnyObserver였다. onNext를 찾아가자. 20 | observer.onNext(1) 21 | observer.onNext(2) 22 | observer.onCompleted() 23 | return Disposables.create() 24 | } 25 | 26 | /* 여행 1 ~ 3 정리 */ 27 | // 지금까지의 여행을 통해 알 수 있는건 두 가지 였다. 28 | // 1. create로 만드는건 Observable 타입이고, 메서드 호출 시 전달되는 클로저의 인자는 AnyObserver이다. 29 | // 2. create의 구현은 ObservableType에 정의되어 있다. 여기서 하는 일은 AnonymousObservable을 만들어 반환하는 것이다. 이때 인자로 전달했던 클로저가 subscribeHandler로 등록된다. 30 | 31 | 32 | /* 여행 4 */ 33 | // 이제 subscribe를 하면 어떤 일이 일어나는지 보자. 34 | // subscribe 메서드 호출의 인자로 네 개의 클로저를 전달했다. 35 | // 그럼 subscribe 메서드의 구현으로 이동해보자. Jump to definition. 36 | let disposable = observable.subscribe( 37 | /* 여행 28 */ 38 | // 도착했다! data에 이벤트의 값이 전달되고, 클로저에 따라 값을 출력한다. 39 | onNext: { data in print(data) }, 40 | onError: { error in print(error) }, 41 | onCompleted: { print("completed") }, 42 | onDisposed: { print("dispose done") } 43 | ) 44 | --------------------------------------------------------------------------------