안녕하세요. 짭짭이 입니다.
금요일이 오고 있어요 ㅠㅠ
요즘에 파이어족 기사를 볼 때 마다 부럽습니다.
1. Rx의 Subscribe를 구현해보는 연습
- Event를 생성 -
RxSwift를 사용할 때마다 클로저를 많이 활용하기 때문에, 정말 구현해보고 싶을 때가 많았습니다.
이렇게 간단한게 구현 연습을 해보으로서 조금 더 성장 할 수 있을 것 같아서 연습을 해봤습니다.
//Generic Type
class Event<T>{
let identifier : String
let result : Result<T, Error>?
init(
identifier : String,
result : Result<T, Error>?
){
self.identifier = identifier
self.result = result
}
}
//sub-class of Event
class UserFetchEvent : Event<[User]> {
}
//Model
struct User : Codable {
let name : String
}
위에 처럼 Event 클래스를 만들어 줍니다. 이것은 고유번호와 Result 타입을 가져서 상태에 따라 결과를 반환 할 수 있도록 해줍니다.
그리고 Event를 상속 받는 UserFetchEvent를 만들어 줍니다.
지금은 아무 것도 없지만 특정한 기능을 사용하고 싶을 때 넣어 줍니다.
- 구독자 전달자인 Bus 객체 생성 -
UserFetchEvent에 대한 구독자와 전달자 역할을 하는 Bus 객체를 생성하도록 하겠습니다.
final class Bus{
static let shared = Bus()
private init() {}
enum EventType{
case userFetch
}
struct Subscription {
let type : EventType
let queue : DispatchQueue
let block : ((Event<[User]>) -> Void)
}
private var subscriptions = [Subscription]()
//구독
func subscribe(
_ event : EventType,
block : @escaping ((Event<[User]>) -> Void)
){
let new = Subscription(type: event, queue: .global(), block: block)
subscriptions.append(new)
}
//구독 in main
func subscribeOnMain(
_ event : EventType,
block : @escaping ((Event<[User]>) -> Void)
) {
let new = Subscription(type: event, queue: .main, block: block)
subscriptions.append(new)
}
//Publish
func publish(_ type : EventType,_ event : UserFetchEvent){
let subscriber = subscriptions.filter({$0.type == type})
subscriber.forEach({ sub in
sub.queue.async {
sub.block(event)
}
})
}
}
subscribe 함수는 Subscription 객체를 생성해서 subscriptions 배열에 넣어줍니다.
Subscription는 (타입 , 쓰레드 , 클로저) 를 가지고 있습니다.
즉, subscribe를 수행하면 Subscription 객체를 생성하고 이 Subscription객체는 block이라는 클로저를 통해
작업을 수행하게 됩니다.
그리고 publish는 전달자로서 타입과 전달할 값을 받아서 subscriptions배열을 타입과 동일 한 것을 찾고
Subscription의 객체의 block에 event(UserFetchEvent)값을 전달해서 정의 된 block을 수행하게 됩니다.
- 뷰를 생성하기 -
class ViewController: UIViewController, UITableViewDataSource {
private var viewModel = UserListViewModel()
private let tableView : UITableView = {
let tbv = UITableView()
tbv.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
return tbv
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(tableView)
tableView.frame = view.bounds
tableView.dataSource = self
Bus.shared.subscribeOnMain(.userFetch, block: {[weak self] event in
guard let result = event.result else {return}
switch result {
case .success(let user):
self?.viewModel.useres = user
self?.tableView.reloadData()
case .failure(let error):
print(error.localizedDescription)
}
})
Bus.shared.subscribe(.userFetch, block: {[weak self] event in
guard let result = event.result else {return}
switch result {
case .success(let user):
print("Global User : \n \(user)")
case .failure(let error):
print(error.localizedDescription)
}
})
viewModel.fetchUserList()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.useres.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = viewModel.useres[indexPath.row].name
return cell
}
}
위에는 그냥 단순히 뷰를 생성한 겁니다.
그런데 중요한 부분은 흐름입니다.
subscribeOnMain함수를 호출하고 block함수를 호출 해줍니다.
그러면 Bus객체에 subscriptions 배열에 해당 block 함수를 가진 Subscription객체를 생성하고 넣어줍니다.
즉, 호출을 기다리는 겁니다.
그리고 ViewModel의 fetchUserList를 통해 호출하게 됩니다.
- ViewModel -
struct UserListViewModel {
var useres : [User] = []
func fetchUserList(){
guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {return}
URLSession.shared.dataTask(with: url) { data, _, _ in
guard let data = data else {return }
let event : UserFetchEvent
do {
let users = try JSONDecoder().decode([User].self, from: data)
event = UserFetchEvent(identifier: UUID().uuidString, result: .success(users))
}
catch{
print(error.localizedDescription)
event = UserFetchEvent(identifier: UUID().uuidString, result: .failure(error))
}
Bus.shared.publish(.userFetch, event)
}.resume()
}
}
이렇게 하면 Publish에 API로 가져온 Event를 전달하게 되고
Publish 함수에서는 타입을 찾고 Subscription객체의 정의된 Block 함수를 수행하게 됩니다.
지금 까지 누가 보면 허접하고 당연한 것을 봤습니다.
나도 파이어족이 되고 싶어용 ㅠ ㅠ
'Xcode > IOS' 카테고리의 다른 글
SwiftUI) LazyGride 대한 경험 정리 (0) | 2022.06.11 |
---|---|
IOS) RxTableViewSectionedReloadDataSource를 실습해보기 (0) | 2021.10.24 |
IOS) Literal에 대해서 알아보자! (0) | 2021.01.31 |
IOS) NSFetchedResultsController을 이용하자! (0) | 2021.01.12 |
IOS) CollectionView에서 특정 Cell에 내용 넣기 In Code (0) | 2021.01.09 |
댓글