์ด์ ๊ธ์์ just
๋ก ๊ฐ๋จํ๊ฒ ๋ฐฉ์ถ์ ๋ณด์๋ค.
์ด๋ฒ ๊ธ์์๋ create
์ ๋ํด ์ข๋ ์ฌ๋ ์๊ฒ ๋ณด๋ฉด์ ์๋ฆฌ๋ฅผ ๋ณด๊ณ ์ ํ๋ค.
Single์ Create
์ด์ ํธ just
๋ก ํ ๊ฒ์ create
๋ก ๋ง๋ค์ด๋ณด์.
// 1. just๋ก ๊ตฌํ
let singleString = Single.just("hi")
// 2. create๋ก ๊ตฌํ
let singleString = Single<String>.create { singleCloser -> Disposable in
singleCloser(.success("hi"))
return Disposables.create()
}
๊ทธ๋ฐ๋ฐ, ์ฌ๊ธฐ์ ํฅ๋ฏธ๋ก์ด ์ ์ create
์ ์๊ทธ๋์ฒ์ด๋ค.
Create ์๊ทธ๋์ฒ์ ์ ๋ ฅ ํ๋ผ๋ฏธํฐ
์๊ทธ๋์ฒ: ๊ฐ๋จํ๊ฒ ๋งํด์ (๋ฉ์๋ ์ด๋ฆ, ํ๋ผ๋ฏธํฐ์ ์ด๋ฆ&์๋ฃํ, ๋ฆฌํด ๊ฐ์ ์๋ฃํ)์ ๋ํ๋ด๋ ๊ฒ
public static func create(subscribe: @escaping (@escaping SingleObserver) -> Disposable) -> Single<Element>
escaping
์ ์ผ๋จ ๋ฌด์ํ๊ณ ํ๋ผ๋ฏธํฐ ๊ฐ๋ง ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
subscribe: (SingleObserver) -> Disposable)
์ฌ๊ธฐ์ SingleObserver
์ ๋ญ๊น? (Disposable
์ ์๋ค๋ ๊ฐ์ ํ์)
public typealias SingleObserver = (SingleEvent<Element>) -> Void
typealias
์ด๊ณ ๋ ๋ค์ ์์ ์๋SingleEvent
๋ ๋ typealias
๋ค.
public typealias SingleEvent<Element> = Result<Element, Swift.Error>
๋๋์ด ์์ ๋ณผ ์ ์๋ ๊ฒ ๊น์ง ๋์๋ค.
์ฆ, subscribe
๋ ํด๋ก์ ์๊ณ , ๊ทธ ํด๋ก์ ์ ์
๋ ฅ ํ๋ผ๋ฏธํฐ ๋ํ ํด๋ก์ ์๋ค.
์ Result
๋ฅผ ์ด์ฉํด์ ์ฑ๊ณต
๊ณผ ์คํจ
๋ฅผ ๋ํ๋ธ ๊ฒ์ด์๋ค.
๋ณ๊ฒ ์๋ค! ๊ทธ์ Observable
์ Result
๋ฅผ ์ด์ฉํ ๊ฒ์ด Single
์ด๋ค.
์ด์ ์ด๋ป๊ฒ ์ด์ฉ์ ํ๋์ง create
๋ฉ์๋์ ๋ด์ฉ์ ๋ณด์.
create ๋ด์ฉ
// 1. Observable ์์ฑ
let source = Observable<Element>.create { observer in
// 2. ์
๋ ฅ ํ๋ผ๋ฏธํฐ์๋ subscribe๋ Disposable์ ๋ฆฌํด ํ๊ธฐ์ return์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
return subscribe { event in
// 3. event๋ Result์ด๋ฏ๋ก switch๋ฅผ ์ด์ฉํ ๋ถ๊ธฐ ์ฒ๋ฆฌ
switch event {
case .success(let element):
// 4. ์
๋ ฅ ๋ฐ์ element๋ฅผ ๊ณง๋ฐ๋ก ๋ฐฉ์ถ.
observer.on(.next(element))
// 5. completed ๋ฐฉ์ถ
observer.on(.completed)
case .failure(let error):
// 6. ์คํจ์ error ๋ฐฉ์ถ
observer.on(.error(error))
}
}
}
// 7. Single<Element> ๋ํ PrimitiveSequence์ typealias์ด๋ค.
return PrimitiveSequence(raw: source)
๋ฉ์๋ ๋ด์ฉ์์ Observable
์ ์์ฑํ์๊ณ , Result
์ ๋ค์๊ณผ ๊ฐ์ด ์ด์ฉํ๋ค.
- ์ฑ๊ณต์:
next
ํcompleted
๋ฐฉ์ถ - ์คํจ์:
error
๋ฐฉ์ถ
์ฑ๊ณต๊ณผ ์คํจ๋ก๋ง ๋๋๊ธฐ ์ํด์ Observable
๊ณผ Result
๋ฅผ ์ด๋ป๊ฒ ์์ฉํ๋์ง ์ ์ ์๋ ๋ถ๋ถ์ด๋ค.
create ์๊ทธ๋์ฒ์ escaping
์ฃผ์ 1
์ ๋ณด๋ฉด Observable<Element>.create
๋ผ๋ ๋ถ๋ถ ๋ํ ํด๋ก์ ์ด๋ฉฐ,
์ด๊ฒ ๋ํ escaping
์ผ๋ก ์์ฑ๋์ด ์๊ธฐ ๋๋ฌธ์ ๊ทธ ์์์ ์ฃผ์2
์ ๊ฐ์ด subscribe
๋ฅผ ์ฐ๊ธฐ ์ํด์ escaping
์ด ์์ด์ผํ๋ค.
์ด๊ฒ ์๊ทธ๋์ฒ์ ์๋ ์ฒซ๋ฒ์งธ escaping
์ ์ด์ ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด, ์๊ทธ๋์ฒ์ ๋๋ฒ์งธ escaping
์ ์ ํ์ํ ๊ฒ์ผ๊น?
์ด๊ฒ์ ๊ธ์ ์ฒซ๋ฒ์งธ ์ฝ๋ ๋ธ๋ก์ผ๋ก ๊ฐ๋ณด์.
let singleString = Single<String>.create { singleCloser -> Disposable in
singleCloser(.success("hi"))
return Disposables.create()
}
singleCloser
๋ผ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค.
์ฌ๊ธฐ์ ๋ง์ฝ ์ง๊ธ ๋น์ฅ success
๋ failure
๋ฅผ ๋ฃ์ ์ ์๋ค๋ฉด?
ํต์ ๊ณผ ๊ฐ์ด ๊ฐ์ ์ง๊ธ ๋น์ฅ ๋ณด๋ผ ์ ์๊ณ , ์บก์ณํ๊ณ ํ์ ์ฒ๋ฆฌ๋ฅผ ํด์ผํ๋ค๋ฉด ์๋์ฒ๋ผ ์์ฑ๋ ๊ฒ์ด๋ค.
let singleString = Single<String>.create { singleCloser -> Disposable in
let url = URL(string: "www.naver.com")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// 1. ํต์ ํ ๋ถ๊ธฐ ์ฒ๋ฆฌ
guard data != nil else {
// 2. ์คํจ ์๋ฌ ๋ฐฉ์ถ
let error = NSError(domain: "", code: 0, userInfo: nil)
singleCloser(.failure(error))
return
}
// 3. ์ฑ๊ณต ๋ฐฉ์ถ
singleCloser(.success("Hi"))
}
task.resume()
return Disposables.create()
}
์ฌ๊ธฐ์ singleObserver
๋ํ ์บก์ณ๊ฐ ๋๊ธฐ ์ํด์ ๋๋ฒ์งธ escaping
์ ๋ฃ์ด์ฃผ์ง ์๋๋ค๋ฉด ์ด๋ฐ ์ค๋ฅ๊ฐ ๋์จ๋ค.
Escaping closure captures non-escaping parameter 'singleCloser'
๋ฐ๋ผ์ singleCloser
๋ escaping
์ด ๋ถ์ด์ผํ๋ค.
์ด๊ฒ ๋๋ฒ์งธ ์ด์ ์ด๋ค.
๋ง๋ฌด๋ฆฌ
์ด๋ ๊ฒ ์ฐ๋ค๋ณด๋ ์๊ฐ์ด ์๊ฐ๋ณด๋ค ์ค๋๊ฑธ๋ ธ๋ค. ์์๋ค ์ถ์๋๋ฐ, ์ ๋ฆฌ์๋ ์ญ์ ๋ณ๊ฐ์๋ค.
Single
์ ํ์คํ ํต์ ๊ณผ ์ ์ด์ธ๋ฆฐ๋ค ์๊ฐ์ด ๋๋ค. ์์ผ๋ก๋ ํต์ ๋ชจ๋ ๋ถ์ผ๋ ์ ๊ทน์ ์ผ๋ก ๋์
์ ํด๋ด์ผ๊ฒ ๋ค.
๋!