Patrón de diseño de delegación de iOS -- ios campo con swift campo con delegates campo con mvp camp codereview Relacionados El problema

iOS delegation design pattern


6
vote

problema

Español

Estoy trabajando en un proyecto que tiene una estructura de presentador de visor modelo y use el patrón de diseño de la delegación que tiene la siguiente estructura / implementación. Me encantaría la retroalimentación.

El ViewController configurará la tríada MVP:

  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)     } }   

El presentador se establecerá como el observador tanto para la vista como para el modelo:

  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)     } }   

El BookView tendrá un protocolo definido:

  protocol BookViewObserver: class {      func evt_bookView(bookView: BookView, didSelectItem: Book) }   

Una acción de usuario en la capa Vista emitirá un evento al presentador:

  class BookView: UIView, UITableViewDataSource, UITableViewDelegate {      weak var observer: BookViewObserver?      func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {         observer?.evt_bookView(self, didSelectItem: books[indexPath.row])     } }   

El presentador implementará el protocolo 9988776665544335 , y maneje ese evento emitido:

  class BookPresenter: BookModelObserver, BookViewObserver {      func evt_bookView(bookView: BookView, didSelectItem book: Book) {         model.updateCurrentBook(book)     } }   

El BookModel tendrá un protocolo definido:

  protocol BookModelObserver: class {      func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook currentBook:     Book) }   

El modelo se actualizará y emitirá un evento de nuevo al presentador:

  class BookModel {      private(set) var currentBook: Book!     weak var observer: BookModelObserver?      func updateCurrentBook(book: Book) {         currentBook = book         observer?.evt_bookModel(self, didUpdateCurrentBook: currentBook     } }   

El presentador implementará el protocolo 99887766655443310 y maneje ese evento emitido. En algunos casos, tiene que actualizar la vista nuevamente y, por lo tanto, llamará a una función en el 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) } } 1 .

  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)     } } 2  

Finalmente, la vista se actualizará a sí misma, trayendo todo Círculo completo:

  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)     } } 3  
Original en ingles

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)     } } 
           

Lista de respuestas

2
 
vote
  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!)     } }   

Veo algunos problemas en este bloque de código solo.

En última instancia, esto podría ser escrito mucho más simplemente como:

  func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook book: Book) {     for (key, value) in DataStore.defaultInstance.books.enumerate() where value.id == book.id {         bookView.updateBook(book, atIndex: index)         break     } }   

Esto elimina una variable y mejor aún, elimina una fuerza de desenvolver (que ni siquiera es necesaria si acaba de usar el if let correctamente).


  class BookModel {      private(set) var currentBook: Book!     weak var observer: BookModelObserver?      func updateCurrentBook(book: Book) {         currentBook = book         observer?.evt_bookModel(self, didUpdateCurrentBook: currentBook)     } }   

Tenemos problemas opcionales más innecesarios en esta clase. No hay una razón particularmente buena para currentBook para ser envuelto implícitamente opcional en este caso. No puede causar nada más que problemas.

Actualmente no hay nada más para esta clase, por lo que no está claro por qué necesitamos mantener una referencia al libro en absoluto, pero nuestro 9988776665544335 puede cambiarse ligeramente para hacer lo mismo, no necesita ninguna Desenvolver el código, y no necesita la opción opcional sin envoltura implícitamente (lo que nuevamente solo se prestará a un desbordamiento de la pila de futuro "Error fatal encontrado nil mientras se desenvuelve opcional" Pregunta).

  class BookModel {     private(set) var currentBook: Book?     weak var observer: BookModelObserver?      func updateCurrentBook(book: Book) {         currentBook = book         observer?.evt_bookModel(self, didUpdateCurrentBook: book)     } }   

Por supuesto, esto podría ser aún mejor si solo usamos el método 99887766655443377665544337 propiedad del observador de propiedades en la propiedad en sí:

  class BookModel {     private(set) var currentBook: Book? {         didSet {             if let newBook = currentBook {                 observer?.evt_bookModel(self, didUpdateCurrentBook: newBook)             }         }     }      weak var observer: BookModelObserver? }   

Pero ahora parece extraño que currentBook podría establecerse en func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook book: Book) { for (key, value) in DataStore.defaultInstance.books.enumerate() where value.id == book.id { bookView.updateBook(book, atIndex: index) break } } 0 y los observadores de la propiedad no se notifican de eso. Así que aquí está lo que tiene más sentido para mí:

  func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook book: Book) {     for (key, value) in DataStore.defaultInstance.books.enumerate() where value.id == book.id {         bookView.updateBook(book, atIndex: index)         break     } } 1  

En este caso, la propiedad 99887766555443312 siempre tiene un buen valor.

O, alternativamente, lo hacemos completamente opcional. No importa si es público o privado.

Aquí está el mayor problema con su implementación original:

  func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook book: Book) {     for (key, value) in DataStore.defaultInstance.books.enumerate() where value.id == book.id {         bookView.updateBook(book, atIndex: index)         break     } } 3  

Esto quizás no sea la intención de usar la clase, pero nada sobre su código evita este uso.

Mi muestra evita el inicializador vacío y obliga a esto:

  func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook book: Book) {     for (key, value) in DataStore.defaultInstance.books.enumerate() where value.id == book.id {         bookView.updateBook(book, atIndex: index)         break     } } 4  

Aquí, la propiedad 99887776655443315 nunca puede ser nil. Y el Código de Observadores de la Propiedad se maneja de una manera más rápida y estándar en comparación con el tipo de enfoque SWIFT-Weird Setter en la implementación original.

 
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!)     } } 

I see a few problems in this block of code alone.

Ultimately, this could be written far more simply as:

func evt_bookModel(bookModel: BookModel, didUpdateCurrentBook book: Book) {     for (key, value) in DataStore.defaultInstance.books.enumerate() where value.id == book.id {         bookView.updateBook(book, atIndex: index)         break     } } 

This eliminates a variable, and better yet, eliminates a force unwrap (that isn't even necessary if you just used the if let correctly).


class BookModel {      private(set) var currentBook: Book!     weak var observer: BookModelObserver?      func updateCurrentBook(book: Book) {         currentBook = book         observer?.evt_bookModel(self, didUpdateCurrentBook: currentBook)     } } 

We've got more unnecessary optional problems in this class. There's not a particularly good reason for currentBook to be an implicitly unwrapped optional in this case. It can cause nothing but problems.

There's currently nothing else to this class, so it's unclear why we need to keep a reference to the book at all, but our updateCurrentBook can be changed slightly to do the same thing, not need any unwrapping code, and not need the implicitly unwrapped optional (which again is only going to lend itself to a future Stack Overflow "fatal error found nil while unwrapping optional" question).

class BookModel {     private(set) var currentBook: Book?     weak var observer: BookModelObserver?      func updateCurrentBook(book: Book) {         currentBook = book         observer?.evt_bookModel(self, didUpdateCurrentBook: book)     } } 

Of course, this might be even better if we just used the didSet property observer method on the property itself:

class BookModel {     private(set) var currentBook: Book? {         didSet {             if let newBook = currentBook {                 observer?.evt_bookModel(self, didUpdateCurrentBook: newBook)             }         }     }      weak var observer: BookModelObserver? } 

But now it seems weird that currentBook could be set to nil and the property observers not notified of that. So here's what makes most sense to me:

class BookModel {     var currentBook: Book {         // a willSet probably also makes sense         didSet {             observer?.evt_bookModel(self, didUpdateCurrentBook: newBook)         }     }      weak var observer: BookModelObserver?      init(book: Book, observer: BookModelObserver? = nil) {         self.book = book         self.observer = observer     } } 

In this case, the book property always has a good value.

Or, alternatively, we make it fully optional. It doesn't matter if it's public or private.

Here's the biggest problem with your original implementation:

let fooBookModel = BookModel() let fooBook: Book = fooBookModel.currentBook // crash, book is nil, it was never set 

This is perhaps not how the class is intended to be used, but nothing at all about your code prevents this usage.

My sample prevents the empty initializer and forces this:

let barBook = Book() let fooBookModel = BookModel(barBook) let fooBook = fooBookModel.currentBook 

Here, the currentBook property can never be nil. And the property observer code is handled in a far more Swift-standard way versus the sort of Swift-weird setter approach in the original implementation.

 
 

Relacionados problema

3  TIC TAC TOE implementado en formas de WinForm usando Model-Viewer-Presenter Pattern  ( Tic tac toe implemented in winforms using model viewer presenter pattern ) 
Tuve que construir una aplicación de 2 jugadores TIC TAC TOE en C # W / WinForms para una pantalla de pre-entrevista. Pasé en esa etapa con éxito y la aplicac...

4  Usando el tipo de tipo decimal o entidad incorporado, para mantener avanzado  ( Using built in type decimal or entity type advance to hold advanceamount ) 
En un sistema de procesamiento salarial que los empleados patrón MVP tenemos clases de modelos WageInfo , EarningInfo1 , 99887776655443322 y AdvanceInfo3...

5  Model-View-Presenter WinForms App  ( Model view presenter winforms app ) 
Este es mi primer intento en una aplicación de formas de formación de patrones de visualización modelo. El modelo es un Duration4 que almacena un montón de ...

3  Empleado Salario / Salario Cálculo MVP Solución - Seguimiento  ( Employee wage salary calculation mvp solution follow up ) 
Este es un seguimiento para esta publicación . En este proyecto (C # gana formularios), se supone que debo calcular los salarios de los empleados. Estos ...

2  Empleado Salario / Salario Cálculo MVP Solución  ( Employee wage salary calculation mvp solution ) 
En este proyecto (C # gana formularios), se supone que debo calcular los salarios de los empleados. Estos son los pasos: Calcular las ganancias de los d...

4  Herramienta de conversión y sello de tiempo PDF  ( Pdf conversion and time stamp tool ) 
Esta es la última edición de mi herramienta PDF, mencionada anteriormente aquí , Aquí , aquí , e inspirado en mi primer intento en un MVP aquí . Difere...

1  Usando modelos y entidades en el patrón MVP  ( Using models and entities in mvp pattern ) 
Soy un principiante en el patrón de diseño de MVP y en una tríada de MVP, tengo modelo - AdvanceInfo view - AdvanceForm presentador - Advance...

12  Generador de tableros de canales y escaleras (junio de 2016 Desafío comunitario)  ( Chutes ladders board generator june 2016 community challenge ) 
Esta es una "entrada" que hice para el desafío comunitario de junio de 2016 para hacer un generador de canales y escaleras. Genera un número aleatorio de cana...

18  Por el agujero de conejo con mvp  ( Down the rabbit hole with mvp ) 
seguimiento en esta publicación donde implementé un patrón de repositorio en < una clase = "post-tag tag" href = "/ Preguntas / etiquetadas / VBA" rel = "e...

5  Model-View-Presenter  ( Model view presenter ) 
Trabajo en una aplicación .NET que sigue de forma muy apósito para un tipo de arquitectura de N-Tier (los objetos de negocios (no lógica) y el acceso a los da...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos