์๋ ํ์ธ์ Foma๐ป ์ ๋๋ค!
์ ๋ฒ ์๊ฐ์ Memo๊น์ง ์ด๋ํด์ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๋ ๊ฒ๊น์ง ๊ตฌํํ์๋๋ฐ์.
์ค๋์ Memoํ๋ฉด์์ ์ผ์ด๋๋ ์ญ์ ,์์ ์ ๊ตฌํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ฐ๋ก ์์ํ ๊ฒ์~
MemoViewController.storyboard
์คํ ๋ฆฌ๋ณด๋ ํ๋ฉด ๊ตฌ์ฑ์ ์๋์ ๊ฐ์ต๋๋ค.
๋ทฐ์ปจํธ๋กค๋ฌ์ ํ ์ด๋ธ๋ทฐ๋ฅผ ๋ฃ์ด์ฃผ๊ณ
ํ ์ด๋ธ๋ทฐ ์ ์ MemoTableViewCell์ ๋ฐ๋ก ๋ง๋ค์ด์ฃผ์์ต๋๋ค.
ํ ์ด๋ธ๋ทฐ์ ์ ์ ๋ณด๋ฅผ ํ์ํด์ค Label,์ญ์ ๋ฒํผ.๋ํ๊ธฐ๋ฒํผ์ผ๋ก ๊ตฌ์ฑ๋์ด์์ต๋๋ค.
Memo
๋ฉ๋ชจ๋ ๊ฐ๋จํ๊ฒ ์ซ์๋ง ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ค๋๋ค.
struct Memo {
let number:Int
}
MemoData
์๋ ์๋ฒ์ ํต์ ์ ํด์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผํ์ง๋ง...๊ท์ฐฎ์ผ๋๊น .. ์ ์ญ์ผ๋ก ์ ์ธํ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ์ธํ ํด๋๊ฒ ์ต๋๋ค.
var MEMO_DATA:[Memo] = [
Memo(number: 1),
Memo(number: 2),
Memo(number: 3),
Memo(number: 4),
Memo(number: 5),
Memo(number: 6),
Memo(number: 7),
Memo(number: 8),
Memo(number: 9),
Memo(number: 10),
Memo(number: 11),
Memo(number: 12),
Memo(number: 13),
Memo(number: 14),
Memo(number: 15),
Memo(number: 16),
Memo(number: 17),
Memo(number: 18),
Memo(number: 19),
Memo(number: 20),
]
MemoTableViewCell
์คํ ๋ฆฌ๋ณด๋์์ ๋ฒํผ๊ณผ ๋ ์ด๋ธ์ ์ฐ๊ฒฐํด์ฃผ๊ณ
RxCocoa,RxSwift๋ฅผ import ํด์ค๋๋ค.
๊ทธ๋ฆฌ๊ณค ์ญ์ ๋ฒํผ๊ณผ ๋ํ๊ธฐ๋ฒํผ์ ๋๋ ์ ๋์ ์ก์ ์ ์ต์ ๋ฒ๋ธ๋ก ๋ง๋ค์ด์ค๋๋ค.
import UIKit
import RxSwift
import RxCocoa
class MemoTableViewCell: UITableViewCell {
@IBOutlet weak var plusButton: UIButton!
@IBOutlet weak var deleteButton: UIButton!
@IBOutlet weak var title: UILabel!
override func prepareForReuse() {
disposeBag = DisposeBag()
}
var disposeBag:DisposeBag = DisposeBag()
var deleteTap : Observable<Void>{
return self.deleteButton.rx.tap.asObservable()
}
var plusTap : Observable<Void>{
return self.plusButton.rx.tap.asObservable()
}
}
MemoViewController
์๋์ ๊ฐ์ด 4๊ฐ ๋ชจ๋์ import ํด์ค๋๋ค.
import RIBs
import UIKit
import RxCocoa
import RxSwift
PresentableListener์ ์ ๋ณด๋ฅผ ๊ฐ์ง๋ memos ๋ฉ๋ชจ๋ทฐ์ปจํธ๋กค๋ฌ์์ ์ผ์ด๋ ์ก์ ์ธ deleteMemo,plusMemo๋ฅผ ๋ฏธ๋ฆฌ ์ ์ํด์ค๋๋ค.
protocol MemoPresentableListener: AnyObject {
var memos: BehaviorRelay<[Memo]> { get }
func deleteMemo(_ index:Int)
func plusMemo(_ index: Int)
}
๊ฐ์ฅ ๋จผ์ ํ ์ด๋ธ๋ทฐ๋ฅผ ์ฐ๊ฒฐํด์ฃผ๊ณ
ํ ์ด๋ธ๋ทฐ์ ๋ฐ์ธ๋ฉ์ ํด์ค bindํจ์๋ฅผ ์์ฑํฉ๋๋ค.
bind()
listener๋ฅผ ํตํด์ memos ์์ ์๋ ์ ๋ณด๋ฅผ ํ ์ด๋ธ๋ทฐ์ ๋ฐ์ธ๋ฉํฉ๋๋ค.
cell์์ ์๋ deleteTap๊ณผ plusTap์ ๊ตฌ๋ ํ์ฌ ์ก์ ์ ๋ํ ํ๋์ PresentableListener ๋ฏธ๋ฆฌ ์ ์ํด๋์๋ deleteMemo์
plusMemo๊ฐ ์คํ๋๋๋ก ํฉ๋๋ค.
final class MemoViewController: UIViewController, MemoPresentable {
@IBOutlet weak var table: UITableView!
weak var listener: MemoPresentableListener?
let disposeBag:DisposeBag = DisposeBag()
static func instantiate() -> Self {
return Storyboard.MemoViewController.instantiate(self)
}
override func viewDidLoad() {
configure()
bind()
}
private func configure() {
self.title = "Memo"
}
private func bind() {
listener?.memos.bind(to: table.rx.items(cellIdentifier: "MemoTableViewCell")) { [weak self] (index, memo, cell) in
if let cell = cell as? MemoTableViewCell {
cell.number.text = "\(memo.number)"
cell.deleteTap
.subscribe(onNext:{
self?.listener?.deleteMemo(index)
})
.disposed(by: cell.disposeBag)
cell.plusTap
.subscribe(onNext:{
self?.listener?.plusMemo(index)
})
.disposed(by: cell.disposeBag)
}
}.disposed(by: disposeBag)
}
}
MemoInteractor
์ด์ ๋ทฐ์ปจํ ๋กค๋ฌ์์ ์ ์ํ๊ณ ์คํํ memos,deleteMemo,plusMemo์ ๋ํ ๋ก์ง์ ๊ตฌํํด์ค์ผ๊ฒ ์ฃ ?
๋น์ง๋์ค ๋ก์ง์ ๋ด๋นํ๋ ์ธํฐ๋ํฐ๋ก ์ด๋ํฉ๋๋ค.
๊ฐ์ฅ ๋จผ์ memos๋ฅผ BehaviorRelay<[Memo]> ๋ก ๋ง๋ค์ด์ค๋๋ค. (BehaviorRelay๋ฅผ ๋ชจ๋ฅด์๋ ๋ถ๋ค์ ์ฌ๊ธฐ ์์ ๋ด์ฃผ์ธ์!)
๊ทธ๋ฆฌ๊ณค ๋ฉ๋ชจ๋ฐ์ดํฐ๋ฅผ ์ต์ ๋ฒ๋ธํ๊ฒ ๋ฐ์์ค๊ฒ๋ ๋ง๋ค์ด์ค๋๋ค.
๊ทธ๋ฆฌ๊ณค getMemoData๋ฅผ memos๋ ๋ฐ์ธ๋ฉ์ ํด์ฃผ์ด memos๊ฐ memoData๋ฅผ ๊ฐ๊ฒํฉ๋๋ค.
.disposeOnDeactive ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์ธํฐ๋ํฐ๊ฐ ๋นํ์ฑํ๋๋ฉด dispose๋๋๋ก ํฉ๋๋ค.
๋ทฐ์ปจํธ๋กค๋ฌ์์ ๋ฆฌ์ค๋์ memos ๋ฐ์ดํฐ์ ํ ์ด๋ธ๋ทฐ๋ฅผ ๋ฐ์ธ๋ฉ ํด์ฃผ์์ฃ ?
์ธํฐ๋ํฐ์์ memos ๋ฐ์ดํฐ๊ฐ ๋ฐ๋ ๋๋ง๋ค ํ ์ด๋ธ๋ทฐ์ ์ ๋ณด๊ฐ ์๋์ผ๋ก ๊ฐฑ์ ๋ ๊ฒ์ ๋๋ค.
final class MemoInteractor: PresentableInteractor<MemoPresentable>, MemoInteractable {
weak var router: MemoRouting?
weak var listener: MemoListener?
var memos: BehaviorRelay<[Memo]> = BehaviorRelay.init(value: [])
...
override func didBecomeActive() {
super.didBecomeActive()
getMemoData()
.bind(to: memos)
.disposeOnDeactivate(interactor: self)
}
func getMemoData() -> Observable<[Memo]> {
return Observable<[Memo]>.create { observer in
observer.onNext(MEMO_DATA)
return Disposables.create()
}
}
}
๋ทฐ์ปจํธ๋กค๋ฌ์ MemoPresentableListener์ ๋ฏธ๋ฆฌ ํ์ํ ์ก์ ๋ค์ ์ ์ํด๋์์ฃ ?
์ธํฐ๋ํฐ๊ฐ MemoPresentableListener ์ฑํํ์ฌ ์ผ์ด๋ ์ก์ ์ ๋ํ ๋ก์ง์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํฉ๋๋ค.
deleteMemo๋ memos์ ํด๋น index๋ฒ์งธ ๋ฉ๋ชจ๊ฐ ์ญ์ ๋๊ณ memos์ ์ ๋ฌํ๋๋ก ์์ฑํ์๊ณ
plusMemo๋ memos์ ํด๋น index๋ฒ์งธ ์ซ์๊ฐ +1 ๋๋๋ก ๋ง๋ค๊ณ memos์ ์ ๋ฌํ๋๋ก ์์ฑํ์์ต๋๋ค.
// MARK: MemosPresentableListener
extension MemoInteractor: MemoPresentableListener {
func deleteMemo(_ index:Int) {
var newMemos = memos.value
newMemos.remove(at: index)
memos.accept(newMemos)
}
func plusMemo(_ index: Int) {
var newMemos = memos.value
newMemos[index] = Memo(number:newMemos[index].number + 1)
memos.accept(newMemos)
}
}
์คํํ๋ฉด
๋ฉ๋ชจ์์ ๋ํ๊ธฐ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ซ์๊ฐ +1์ฉ ์ฆ๊ฐํ๊ณ ์ญ์ ๋ฅผ ๋๋ฅด๋ฉด ํด๋น ๋ฉ๋ชจ๊ฐ ์ญ์ ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
'๐ iOS > Architecture' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[iOS/Framework] Quick/Nimble์ด ๋ญ๊น? (feat. ์ฌ์ฉ๋ฒ) (0) | 2021.08.31 |
---|---|
[RIBs] AddMemo ๊ตฌํํ๊ธฐ (๋ฉ๋ชจ ์ถ๊ฐํ๊ธฐ) (0) | 2021.08.26 |
[RIBs] Router๋ฅผ ์ด์ฉํด ํ๋ฉด ์ ํํด๋ณด๊ธฐ (feat. Memo) (0) | 2021.08.24 |
[RIBs] Interactor๋ก ๋น๋์ง์ค ๋ก์ง ์ฒ๋ฆฌํด๋ณด๊ธฐ (feat. ์ด๊ธฐ์ธํ ) (0) | 2021.08.18 |
[Design Pattern] RIBs๋?(feat. Uber) (0) | 2021.08.18 |
๋๊ธ