λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🍎 iOS/RxSwift

[iOS] MVVM & RxSwift μŠ€ν„°λ”” W2 - TableView λ§Œλ“€μ–΄λ³΄κΈ°

by Danna 2021. 7. 15.
728x90
728x90
 

iamchiwon/RxSwift_In_4_Hours

RxSwift, 4μ‹œκ°„ μ•ˆμ— λΉ λ₯΄κ²Œ μ΅ν˜€ 싀무에 μ‚¬μš©ν•˜κΈ°. Contribute to iamchiwon/RxSwift_In_4_Hours development by creating an account on GitHub.

github.com

κ³°νŠ€κΉ€λ‹˜ κ°•μ˜ μ˜μƒμ˜ μ½”λ“œλŠ” step1 ~ 4 κΉŒμ§€ μžˆλŠ”λ°μš”. step1 은 JSON νŒŒμΌμ„ λ‹€μš΄λ‘œλ“œν•˜λŠ” μž‘μ—…μ„ λΉ„λ™κΈ°λ‘œ μ²˜λ¦¬ν•˜κ³  이λ₯Ό editView 에 λ„μ›Œμ£ΌλŠ” 것이고. step2 λŠ” step1 κ³Ό 같은 JSON νŒŒμΌμ„ tableView 둜 λ³΄μ—¬μ£ΌλŠ” μ½”λ“œμ—μš”. κ°•μ˜μ—μ„œ step2 λŠ” νŒ¨μŠ€ν•˜μ…”μ„œ 이λ₯Ό μ—°μŠ΅ν•΄λ΄€μŠ΅λ‹ˆλ‹Ή 🧐


πŸ‘€ MVVM + RxSwift TableView 예제 

step2 μ™„μ„± μ½”λ“œμ—μ„œλŠ” 타이머와 LOAD λ²„νŠΌμ΄ μ—†μ§€λ§Œ, λ‹€μš΄λ‘œλ“œ μž‘μ—…μ΄ λΉ„λ™κΈ°λ‘œ λ˜λŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ 타이머와 λ‘œλ”© & 인디케이터 μ• λ‹ˆλ©”μ΄μ…˜μ„ λƒ…λ’€κ³ , LOAD λ²„νŠΌμ„ λˆ„λ₯Όλ•Œλ§ˆλ‹€ 데이터가 κ°±μ‹ λ˜λ„λ‘ ν–ˆμ–΄μš”!

RxSwift + MVVM TableView Example


🌱 MVVM νŒ¨ν„΄ μ μš©ν•˜κΈ°

κ°•μ˜κ°€ MVVM + RxSwift 인 만큼, MVVM νŒ¨ν„΄μœΌλ‘œ κ΅¬λΆ„ν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Όν•˜μ§€? λ₯Ό κ³ λ―Όν–ˆμŠ΅λ‹ˆλ‹€.

μ •ν™•ν•˜κ²Œ κ΅¬λΆ„λ˜μ—ˆμ„ μ§€λŠ” λͺ¨λ₯΄κ² μ§€λ§Œ.. λ‹€μŒκ³Ό 같이 Model / View / View Model 을 κ΅¬λΆ„ν–ˆμ–΄μš”.

 

Model 은 κΈ°μ‘΄ MVC μ—μ„œλ„ λͺ¨λΈμ΄λ‹ˆκΉŒ λ™μΌν•˜μ§€λ§Œ, View / View Model 뢄리가 μ–΄λ €μ› μ–΄μš” πŸ₯Ί

둜직 κ΄€μ μ—μ„œ ν•„μš”ν•œ μ½”λ“œλŠ” View Model, UI κ΄€μ μ—μ„œ ν•„μš”ν•œ μ½”λ“œλŠ” View Controller 에 μž‘μ„±ν•œλ‹€κ³  μƒκ°ν•˜μ‹œλ©΄ λ©λ‹ˆλ‹€!

1. Model - View 에 보여쀄 데이터

  • members - List View Controller μ—μ„œ TableView 에 보여쀄 Member νƒ€μž…μ˜ 배열인 λͺ¨λΈ 데이터
  • selectedMember - Detail View Controller μ—μ„œ μƒμ„Έν•˜κ²Œ 보여쀄 Member νƒ€μž…μ˜ λͺ¨λΈ 데이터

Member ꡬ쑰체 vs JSON data ν˜•νƒœ

 

 

2. View (View Controller) - UI μž‘μ—…λ“€

  • TableView, Cell λ“± UI 와 κ΄€λ ¨λœ μž‘μ—…μ€ μŠ€ν† λ¦¬λ³΄λ“œλ‘œ μ§„ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.
  • View, View Controller μ—μ„œ 데이터λ₯Ό μ ‘κ·Όν•  λ•Œμ—λŠ” view Model 을 톡해 μ ‘κ·Όν•˜λ„λ‘ ν•©λ‹ˆλ‹€!
  • TableView 에 데이터λ₯Ό 그리기 μœ„ν•΄ BehaviorSubject 인 members μ—  tableView.rx.items λ₯Ό bind ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. * UITableViewDataSource ν”„λ‘œν† μ½œμ˜ κΈ°λ³Έλ©”μ†Œλ“œμ„ κ΅¬ν˜„ν•˜λŠ” 것과 동일함.
  • TableView 의 각 Cell 을 λˆ„λ₯Όλ•Œλ§ˆλ‹€ Detail VC 둜 μ΄λ™ν•˜κΈ° μœ„ν•΄, tableView.rx.modelSelected λ₯Ό subscribe ν•˜μ—¬, Detail VC 둜 μ΄λ™ν•˜κ²Œλ” ν–ˆμŠ΅λ‹ˆλ‹€. * UITableViewDelegate ν”„λ‘œν† μ½œμ˜ didSelectRowAt λ©”μ†Œλ“œμ™€ 동일함.
  • μΆ”κ°€μ μœΌλ‘œ κ³ λ €ν•΄μ•Όν•  뢀뢄은 UITableViewCell κ³Ό DetailVC μ—μ„œ 이미지 λ‹€μš΄λ‘œλ“œμ— λŒ€ν•œ μž‘μ—…μž…λ‹ˆλ‹€!
  • Member κ΅¬μ‘°μ²΄λŠ” avatar 이미지에 λŒ€ν•œ url 만 가지고 있기 λ•Œλ¬Έμ—, 이λ₯Ό λ‹€μ‹œ ν•œλ²ˆ λΉ„λ™κΈ°λ‘œ λ‹€μš΄λ‘œλ“œν•˜λŠ” μž‘μ—…μ΄ ν•„μš”ν•΄μš”!

πŸ‘‡ ListViewController / DetailViewController / MemberCell μžμ„Ένžˆλ³΄κΈ°

 

[iOS] MVVM & RxSwift μŠ€ν„°λ”” W2 - TableView bind items, modelSelected, cell prepareForReuse

[iOS] MVVM & RxSwift μŠ€ν„°λ”” W2 - TableView λ§Œλ“€μ–΄λ³΄κΈ° iamchiwon/RxSwift_In_4_Hours RxSwift, 4μ‹œκ°„ μ•ˆμ— λΉ λ₯΄κ²Œ μ΅ν˜€ 싀무에 μ‚¬μš©ν•˜κΈ°. Contribute to iamchiwon/RxSwift_In_4_Hours development by creating..

jellysong.tistory.com

 

3. View Model - μ‹€μ œ 둜직 κ΄€λ ¨λœ μž‘μ—…

  • View Model 은 UI에 독립적이며, μ‹€μ œ λ‘œμ§μ— κ΄€λ ¨λœ μž‘μ—…λ“€μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€! * UI 와 λ…λ¦½μ μ΄λ―€λ‘œ Testable ν•©λ‹ˆλ‹€.
  • View Model μ€ model 을 κ°–κ³  있으며, ν•΄λ‹Ή μ˜ˆμ œμ—μ„œλŠ” members, selectedMember λΌλŠ” λͺ¨λΈμ„ 가지고 μžˆμŠ΅λ‹ˆλ‹€.
  • 사싀 이 μ˜ˆμ œλŠ” λͺ¨λΈμ„ κ°€κ³΅ν•˜λŠ” μž‘μ—…μ΄ μ—†κΈ° λ•Œλ¬Έμ—, JSON 데이터λ₯Ό λΉ„λ™κΈ°λ‘œ λ‹€μš΄λ‘œλ“œλ°›μ•„ μ €μž₯ν•˜λŠ” μž‘μ—…λ§Œ μˆ˜ν–‰ν•˜κ³  μžˆμ–΄μš”.
  • 이 λ•Œ, APIManager.fetchData λ©”μ†Œλ“œλ₯Ό 톡해 λ°˜ν™˜λ°›μ€ Observable<Data> λ₯Ό subscirbe ν•˜μ—¬ onNext 이벀트 λ°œμƒ μ‹œ, map 을 톡해 data -> [Member] 둜 λ§Œλ“€μ–΄μ£Όκ³ , ν•΄λ‹Ή 배열을 κ°–κ³  members (Subject) 의 onNext λ₯Ό λ°©μΆœν•˜λ„λ‘ ν•©λ‹ˆλ‹€.
import Foundation
import RxSwift

class MemberViewModel {

    static let shared = MemberViewModel() // singleton
    var members = BehaviorSubject<[Member]>(value: [])
    var selectedMember = Member.EMPTY

    init() {
        reloadData()
    }
    
    func reloadData() {
        // Observable<Data> --> subscribe --> members
        _ = APIManager.fetchData(url: APIManager.MEMBER_LIST_URL)
            .map { data -> [Member] in
                let members = try! JSONDecoder().decode([Member].self, from: data)
                return members
            }
            .take(1) // λ²„νŠΌ λˆ„λ₯Ό κ²½μš°μ—λ„ ν˜ΈμΆœλ˜λ―€λ‘œ, 1번만 μˆ˜ν–‰ν•˜κ²Œλ” 함
            .subscribe(onNext: { self.members.onNext($0) })
    }
}

 

4. APIManager - λ„€νŠΈμ›Œν¬ λ‹€μš΄λ‘œλ“œ 비동기 μž‘μ—…

  • URLSession 을 톡해 data λ₯Ό λ‹€μš΄λ‘œλ“œν•˜λŠ” 비동기 μž‘μ—…μ„ λ”°λ‘œ APIManager 클래슀 내에 λ©”μ†Œλ“œλ‘œ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
  • APIManager.fetchData(url:) λ©”μ†Œλ“œλŠ” Observable<Data> λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
  • 이 λ©”μ†Œλ“œλ₯Ό 톡해 μƒμ„±λœ Observable<Data> λ₯Ό subscribe ν•˜μ—¬ members λͺ¨λΈ 값을 λ³€ν™˜μ‹œν‚€κ³ ,
  • 이미지 λ‹€μš΄λ‘œλ“œ μž‘μ—…μ‹œμ—λ„ Observable<Data> λ₯Ό subscribe ν•˜μ—¬ UIImage 둜 λ³€ν™˜ν•˜λ„λ‘ κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.
import Foundation
import RxSwift

class APIManager {
    
    static let MEMBER_LIST_URL = "https://my.api.mockaroo.com/members_with_avatar.json?key=44ce18f0"
    
    // JSON url -> Observable<Data> // --(subscribe)--> Member model
    // Image url -> Observable<Data> // --(subscribe)--> UIImage
    
    static func fetchData(url: String) -> Observable<Data> {
        return Observable.create() { emitter in
            let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in
                // 데이터 μˆ˜μ‹  μ‹€νŒ¨
                if let error = error {
                    emitter.onError(error)
                    return
                }
                // 데이터가 없을 λ•Œ http status code 전달
                guard let data = data else {
                    let httpResponse = response as! HTTPURLResponse
                    emitter.onError(NSError(domain: "no data", code: httpResponse.statusCode, userInfo: nil))
                    return
                }
                // μ„±κ³΅ν•œ 경우
                emitter.onNext(data)
                emitter.onCompleted()
            }
            task.resume()
            return Disposables.create {
                task.cancel() // dispose 될 경우
            }
        }
    }
}

 

전체 μ½”λ“œ

 

 

songda515/MVVM_RxSwift

MVVM νŒ¨ν„΄κ³Ό RxSwift λ₯Ό ν•™μŠ΅ν•˜κ³ , 이λ₯Ό μ μš©ν•œ ν”„λ‘œμ νŠΈλ₯Ό κ°œλ°œν•˜κΈ° μœ„ν•œ μŠ€ν„°λ””λͺ¨μž„μž…λ‹ˆλ‹€. - songda515/MVVM_RxSwift

github.com

참고 링크

728x90
728x90