IAM iOS

[RxSwift] TODO List App Using Filter Operations 본문

RxSwift

[RxSwift] TODO List App Using Filter Operations

IAMiOS 2022. 3. 30. 15:07

 

What we will be Building?


우선순위와 함께 작성한 메모를 Segmented Control를 활용하여 TableView에 띄우기

gif라 화질 깨짐 ㅠ,,

 

AddTaskViewController


메모를 작성하는 View에서 선택한 우선순위메모를 메인 View로 넘기기 위해
(프로토콜이나 델리게이트 패턴을 사용하지 않고) RxSwift를 사용하여 task를 전달 !

 

1. enum 타입, 우선순위(Priority)전달할 데이터(Task)를 담은 구조체

enum Priority: Int {
    case high
    case medium
    case low
}

struct Task {
    let title: String
    let priority: Priority
}

 

2. (Subscribe가 가능한) Task를 반환할 Subject를 생성한다.

private let taskSubject = PublishSubject<Task>()

var taskSubjectObservable: Observable<Task> {
    return taskSubject.asObserver()
}

 

3. 우선순위를 체크하고, 메모를 작성한 뒤 저장 버튼을 누르면 task를 담은 Subject 전송한다.

@IBAction func save() {
    guard let priority = Priority(rawValue: self.prioritySegmentedControl.selectedSegmentIndex), 
	   let title = self.taskTitleTextField.text else { return }
    
    let task = Task(title: title, priority: priority)
        
    // Subject 호출, 전송
    taskSubject.onNext(task)
    self.dismiss(animated: true)
}

 


참고

  • 메모를 저장할 때 Segmented Control은 High, Medium, Low만 있고, 메인 View는 All을 포함하고 있으므로 선택한 세그먼트 Index에 -1을 해준다.
let priority = Priority(rawValue: self.prioritySegmentedControl.selectedSegmentIndex - 1)

 

 

TaskListViewController


1. Observable (taskSubjectObservable)을 구독하여 task를 가져온다.

  • addTaskVC에서 전달받은 Task를 담을 BehaviorRelay<[tasks]>
  • BehaviorRelay<[tasks]>[task] 배열을 담기 위해 새로운 배열(existingTasks)을 만든다.

 


참고

  • RxSwift인 Subject와는 다르게 Relay는 RxCocoa의 클래스

BehaviorRelay는 BehaviorSubject의 Wrapper 클래스
value를 통해서 현재의 값을 가져올 수 있으며, Variable이 Deprecate 되면서 대신에 BehaviorRelay를 사용하면 된다.

  • ~Subject~Relay의 차이점

~Subject는 .completed, .error의 이벤트가 발생하면 subscribe가 종료되는 반면,
~Relay는 .completed, .error를 발생하지 않고, Dispose 되기 전까지 계속 작동하기 때문에 UI Event에서 사용하기 적절하다.


 

import RxCocoa

private var tasks = BehaviorRelay<[Task]>(value: [])
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let navC = segue.destination as? UINavigationController,
          let addTVC = navC.viewControllers.first as? AddTaskViewController else { fatalError("Controller not found..")}
        
    // subscribe
    addTVC.taskSubjectObservable
        .subscribe(onNext: { [unowned self] task in
                
            let priority = Priority(rawValue: self.prioritySegmentedControl.selectedSegmentIndex - 1)
                
            var existingTasks = self.tasks.value // [Task]
            existingTasks.append(task)

            self.tasks.accept(existingTasks)
            
            self.filterTasks(by: priority) // Filtering
                
        }).disposed(by: disposeBag)
}

 

2. 우선순위에 따라 작업 Filtering

  • priority == nil (All) → 전체 Task 배열 담기
  • priority == High / Medium / Lowmap을 통해 Filter 작업에 액세스
  • Priority? 옵셔널 처리하는 이유 → Priority에서 All case는 존재하지 않음
private var filteredTasks = [Task]()

...

private func filterTasks(by priority: Priority?) {
        
    if priority == nil { // All
        self.filteredTasks = self.tasks.value
        self.updateTableView()

    } else { // High, Medium, Low
        
        // 매핑 후 필터 처리
        self.tasks.map { tasks in
            return tasks.filter { $0.priority == priority! }

        }.subscribe(onNext: { [weak self] tasks in
            self?.filteredTasks = tasks
            self?.updateTableView()
            
        }).disposed(by: disposeBag)
    }
}

 

3. 해당 Segmented Control을 선택 → 선택한 priority에 해당하는 tasks 배열을 TableView에 띄운다.

@IBAction func priorityValueChanged(segmentControl: UISegmentedControl) {
    let priority = Priority(rawValue: segmentControl.selectedSegmentIndex - 1)
    filterTasks(by: priority)
}

 

  • filteredTasks 배열에 담긴 수만큼 반환
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.filteredTasks.count
}

 

 

코드 보러 가기

 

GitHub - camosss/RxSwift: RxSwift 공부한 내용 정리

RxSwift 공부한 내용 정리. Contribute to camosss/RxSwift development by creating an account on GitHub.

github.com