[RxSwift๐Ÿฆˆ] #6 performSegue / Single, Maybe, Completable

๋˜์ƒยท2022๋…„ 1์›” 17์ผ
0

iOS

๋ชฉ๋ก ๋ณด๊ธฐ
5/42
post-thumbnail

raywenderlich RxSwift Ch1~4

raywenderlich ์˜ RxSwift ์ฑ…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ RxSwift ์ •๋ฆฌ ๋ฅผ ๋ณด๊ณ  ๊ณต๋ถ€ํ•˜๊ณ  ์žˆ๋‹ค. Ch1 ~ Ch3 ์˜ ๊ฒฝ์šฐ๋Š” ์•ž์„œ ์ •๋ฆฌํ–ˆ๋˜ ๊ณฐํŠ€๊น€๋‹˜์˜ ๊ฐ•์˜์—์„œ ๋“ค์€ Observable๊ณผ Subject๋ฅผ ์กฐ๊ธˆ ๋” ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ๋กœ ์‚ดํŽด๋ณด๊ณ  ๋ฌธ์ œ๋„ ํ’€์–ด๋ณด๋Š” ์ •๋„์˜ ๋‚ด์šฉ์ด์—ˆ๋‹ค.



Ch4๋Š” Relay, Subject ๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ์ฝœ๋ผ์ฃผ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜ˆ์ œ์˜€๋‹ค. UI๋Š” ์ด๋ฏธ ๋‹ค ์ž‘์„ฑ๋œ ๋ผˆ๋Œ€ ์œ„์— RxSwift๋ฅผ ์–น์–ด์„œ Clear, Save, + ๋ฒ„ํŠผ์— ๋Œ€ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ์—!


PhotosViewController (์ดํ•˜ PhotosVC), MainViewController (์ดํ•˜ MainVC)

์›๋ž˜ ์ข‹์•„ํ•˜๋Š” ๊ณต๋ถ€ ๋ฐฉ์‹์ธ ์ฝ”๋“œ ์ˆœ์„œ๋Œ€๋กœ ๋”ฐ๋ผ๊ฐ€๋Š” ๊ฒƒ ์ •๋ฆฌํ•˜๊ธฐ์˜ ๊ฒฝ์šฐ๋Š” ์›๊ธ€์—์„œ ๋„ˆ๋ฌด ์ž˜ ํ•ด๋‘์…จ๊ธฐ ๋•Œ๋ฌธ์—, ์ƒˆ๋กœ ์•Œ๊ฒŒ ๋œ ํฌ์ธํŠธ๋“ค์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.


1. VC ์ด๋™ ์‹œ, ๋ฐ์ดํ„ฐ ์ฃผ๊ณ  ๋ฐ›๊ธฐ

MainVC -> PhotosVC ๋กœ ์ด๋™ํ•˜์—ฌ PhotosVC ์—์„œ ์‚ฌ์ง„์„ ๊ณจ๋ผ์„œ MainVC ์— ์‚ฌ์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ค˜์•ผํ•˜๋Š” ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š”, ๋ณดํ†ต delegate ๋ฅผ ์ด์šฉํ•ด์„œ ๋„˜๊ฒจ์ฃผ๊ธฐ ๋งˆ๋ จ์ด๋‹ค. PhotosVC ์—์„œ๋Š” delegate ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•˜๊ณ  ์‹ค ์ฒ˜๋ฆฌ๋Š” MainVC ์˜ ํ•จ์ˆ˜์—์„œ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ, Rx์—์„œ๋Š” delegate ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

Observable ๋กœ ์–‘์ชฝ VC์—์„œ ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„์„ ๊ตฌ๋…ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

// MainVC
@IBAction func actionAdd() {
  let photosVC = storyboard?.instantiateViewController(withIdentifier: "PhotosViewController") as! PhotosViewController
  navigationController?.pushViewController(photosVC, animated: true)
  
  // ๊ทธ ๋Œ€์‹  ์ด๋ ‡๊ฒŒ ์ด๋™ํ•  VC์˜ Observable ์„ ๊ตฌ๋…ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.
  photosVC.selectedPhotos
    .subscribe(onNext: { [weak self] image in
      guard let images = self?.images else { return }
      images.accept(images.value + [image])
    }, onDisposed: {
      print("photo selection completed")
    })
    .disposed(by: disposeBag)
}
// PhotosVC
private var selectedPhotosSubject = PublishSubject<UIImage>()
// MainVC ์—์„œ selectedPhotos์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ์ผ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—, ๋ฐ์ดํ„ฐ์˜ ์ˆ˜์ •์„ ๋ง‰๊ธฐ ์œ„ํ•ด Observable ์„ ๊ตฌ๋…ํ•˜๊ฒŒ ํ•œ๋‹ค.
var selectedPhotos: Observable<UIImage> {
  return selectedPhotosSubject.asObservable()
}

๋Œ€์‹  ์—ฌ๊ธฐ์„œ ์‹ ๊ฒฝ์จ์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์€, MainVC ์—์„œ selectedPhotos ๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, PhotosVC ๊ฐ€ ์—†์–ด์ง„๋‹ค๊ณ  ํ•ด์„œ selectedPhotosSubject ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค.

// PhotosVC
override func viewWillDisappear(_ animated: Bool) {
  super.viewWillDisappear(animated)
    
  selectedPhotosSubject.onCompleted()
}

viewWillDisappear ์—์„œ ๋ช…์‹œ์ ์œผ๋กœ Subject๋ฅผ ์ข…๋ฃŒ์‹œ์ผœ์„œ ํ•ด์ œํ•˜์ž.



2. Single, Maybe, Completable / Custom Observable


Custom Observable ์ฝ”๋“œ๋ฅผ (photo id ํ•˜๋‚˜๋งŒ emit ํ•˜๋Š”) Single ์„ ์ด์šฉํ•ด์„œ refactoring ํ•ด๋ณด์•˜๋‹ค.

  static func save(_ image: UIImage) -> Single<String> {
    // return Observable.create({ observer in
    return Single.create (subscribe: { observer in
      var saveAssetId: String?
      PHPhotoLibrary.shared().performChanges({
        
        let request = PHAssetChangeRequest.creationRequestForAsset(from: image)
        saveAssetId = request.placeholderForCreatedAsset?.localIdentifier
      }, completionHandler: { success, error in
        DispatchQueue.main.async {
          if success, let id = saveAssetId {
//            observer.onNext(id)
//            observer.onCompleted()
            observer(.success(id))
          } else {
            observer(.error(error ?? Errors.couldNotSavePhoto))
          }
        }
      })
      return Disposables.create()
    })
  }
}



3. guard let else { return }

RxSwift ์—์„œ๋งŒ ์“ฐ์ด๋Š” ๋‚ด์šฉ์€ ์•„๋‹ˆ์ง€๋งŒ, ๋ถ€๋ถ„์— ๋ถˆ๋Ÿฌ์™€์•ผ ํ•˜๋Š” ์š”์†Œ ์ค‘ nil ์ด ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒƒ์„ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉํ•˜๋ฉด guard ๋ฌธ ๋’ค๋กœ๋Š” ? ! ๋ฅผ ๋ถ™์ผ ํ•„์š”๊ฐ€ ์—†์–ด์„œ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ ๊ทน ํ™œ์šฉํ•ด์•ผ๊ฒ ๋‹ค.



๋Š๋‚€์ 

์ž˜ ๋ชจ๋ฅด๊ฒ ์„ ๋•Œ๋Š” ํ”„๋กœ์ ํŠธ๋กœ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ณ๋ณด๋Š”๊ฒŒ ์ตœ๊ณ ๋ผ๋Š” ์ƒ๊ฐ์— ๊ทธ๋ƒฅ ์ˆœ์„œ๋Œ€๋กœ ์ญ‰ ๋”ฐ๋ผ์„œ ์ฝ”๋“œ๋ฅผ ํ•œ๋ฒˆ ์น˜๊ณ  ์ตœ๋Œ€ํ•œ ํ๋ฆ„์„ ๊ธฐ์–ตํ•ด๋ณด๋ฉด์„œ ์กฐ๊ธˆ์”ฉ ์น˜ํŒ…ํ•˜๋ฉด์„œ ์ฝ”๋“œ๋ฅผ ๋˜ ์ณ๋ณด๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ณต๋ถ€๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค. ์กฐ๊ธˆ์ด๋‚˜๋งˆ Observable ์„ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ์†์— ์ตํžŒ ๊ฒƒ ๊ฐ™๋‹ค.

์–ด๋Š ์ƒํ™ฉ์—์„œ ์–ด๋–ค ๊ฒƒ์„ ์จ์•ผํ•˜๋Š”์ง€๋Š” ์•„์ง ๊ฐ์ด ์ž˜ ์•ˆ์˜ค์ง€๋งŒ, ๊ฐ•์˜ ์ž๋ฃŒ Challenge ์— ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ Observable๋กœ ๋งŒ๋“ค๊ณ  Single๋กœ ๋ฆฌํŒฉํ† ๋ง ํ•˜๋Š” ๋ฐฉ์‹๋„ ์ข‹์€ ๋ฐฉ์‹์ด๋‹ˆ๊นŒ!!! ์ผ๋‹จ ์ตœ๋Œ€ํ•œ ์ต์ˆ™ํ•ด์ง€์ž.

profile
0๋…„์ฐจ iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€