์ด์ ๊ธ์์ 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์ ํ์คํ ํต์ ๊ณผ ์ ์ด์ธ๋ฆฐ๋ค ์๊ฐ์ด ๋๋ค. ์์ผ๋ก๋ ํต์ ๋ชจ๋ ๋ถ์ผ๋ ์ ๊ทน์ ์ผ๋ก ๋์
์ ํด๋ด์ผ๊ฒ ๋ค.
๋!