I am working on a project that has a Model-View-Presenter structure and use the delegation design pattern that has the following structure/implementation. I would love feedback.
The ViewController will set up the MVP triad:
class BookViewController: UIViewController {
private var bookModel: BookModel!
private var bookView: BookView!
private var bookPresenter: bookPresenter!
override func loadView() {
super.loadView()
bookModel = BookModel()
bookView = BookView()
bookPresenter = BookPresenter(model: bookModel, view: bookView)
view.addSubview(bookView)
}
}
The Presenter will set itself up as the observer to both the View and Model:
class BookPresenter: BookModelObserver, BookViewObserver {
let bookModel: BookModel
var bookView: BookView
init(model: BookModel, view: BookView) {
self.bookModel = bookModel
self.bookView = bookView
self.bookModel.observer = self
self.bookView.observer = self
let book = self.model.currentBook
self.bookView.setData(book)
}
}
The BookView
will have a protocol defined:
protocol BookViewObserver: class {
func evt_bookView(bookView: BookView, didSelectItem: Book)
}
A user action on the View layer will emit an event to the Presenter:
class BookView: UIView, UITableViewDataSource, UITableViewDelegate {
weak var observer: BookViewObserver?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
observer?.evt_bookView(self, didSelectItem: books[indexPath.row])
}
}
The Presenter will implement the BookViewObserver
protocol, and handle that emitted event:
class BookPresenter: BookModelObserver, BookViewObserver {
func evt_bookView(bookView: BookView, didSelectItem book: Book) {
model.updateCurrentBook(book)
}
}
The BookModel
will have a protocol defined:
protocol BookModelObserver: class {
func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook currentBook: Book)
}
The Model will update itself, and emit an event back up to the Presenter:
class BookModel {
private(set) var currentBook: Book!
weak var observer: BookModelObserver?
func updateCurrentBook(book: Book) {
currentBook = book
observer?.evt_bookModel(self, didUpdateCurrentBook: currentBook
}
}
The Presenter will implement the BookModelObserver
protocol, and handle that emitted event. In some cases, it has to update the View again, and thus will call a function on the BookView
.
class BookPresenter: BookModelObserver, BookViewObserver {
func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook book: Book) {
var index: Int?
for (key, value) in DataStore.defaultInstance.books.enumerate() {
if value.id == book.id {
index = key
break
}
}
if let _ = index {
bookView.updateBook(book, atIndex: index!)
}
}
}
Finally the View will update itself, bringing everything full circle:
class BookView: UIView, UITableViewDataSource, UITableViewDelegate {
func updateData(book: Book, atIndex index: Int) {
books[index] = book
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: UITableViewRowAnimation.None)
}
}