Блокировать обратные вызовы или протоколы для передачи информации между DataManager и Interactor в VIPER?

Когда используешь Objective-C который является предпочтительным методом для передачи объектов из DataManager к Interactor при использовании VIPER архитектурный образец.

В частности использование Block Based Callbacks против DataManager Output Protocol

Приложение Sample To Do из оригинальной статьи Mutual Mobile о VIPER

использования Block Based Callbacks вот так

- (void)todoItemsBetweenStartDate:(NSDate *)startDate endDate:(NSDate *)endDate completionBlock:(void (^)(NSArray *todoItems))completionBlock;

Принимая во внимание, что этот подход от Бригады Инжиниринг

использует OutputProtocol на DataManager

[self.interactor foundUser:user];

Какой метод лучше и почему?

Примечание: я знаю, что при использовании Swift замыкания могут сделать метод обратного вызова намного чище. Этот вопрос имеет прямое отношение к Objective-C.

2 ответа

Решение

Я предпочитаю по возможности использовать протокол вывода, поскольку это облегчает тестирование. Проще использовать протокол вывода, когда есть только один слушатель. Если имеется несколько прослушивателей, проще использовать блок обратного вызова, чтобы объект не отслеживал получателя для каждого запроса.

Я считаю, что выходные протоколы проще тестировать, потому что вы можете напрямую вызвать слушателя. Например, Presenter обычно реализует выходной протокол Interactor. Допустим, у нашего выходного протокола Login Interactor есть два метода:

- (void)didLogin - (void)loginFailedWithError:(NSError*)error

При тестировании Login Presenter, мы хотим написать тесты для случая, когда вход в систему успешен и когда сбой входа в систему. Тест на успешный вход в систему можно позвонить напрямую [presenter didLogin]; а тест на провал можно напрямую вызвать [presenter loginFailedWithError:badCredentialsError];,

Если бы вместо этого мы использовали блок обратного вызова, интерфейс Login Interactor мог бы выглядеть примерно так:

- (void)loginWithUsername:(NSString*)username password:(NSString*)password result:(void (^)(NSError* error))block;

При тестировании докладчика, чтобы проверить успешный вариант, вам нужно будет заглушить метод входа в Interactor, чтобы вернуть успех, а затем вызвать метод в Presenter, который заставит его выполнить запрос на вход в Interactor.

[interactor willSucceed]; [presenter login];

Это делает ваш тест менее ясным в отношении реальных намерений.

Если вы сможете разработать свой API DataManager для поддержки протокола вывода, это облегчит тестирование. Если нет, я бы не беспокоился об этом, а просто использовал бы блок обратного вызова.

Это не сухо, но:

  1. Стремитесь отдавать предпочтение блокам завершения, если есть только один обратный вызов.
  2. Стремитесь отдать предпочтение протоколу / делегированию, если есть семейства связанных обратных вызовов.

Возможно, вы могли бы использовать другую эвристику (например, делегирование лучше, если, вероятно, существует очевидный объект для реализации протокола, и его нужно будет реализовать только один раз).

Вы видите, как оба используются в рамках Apple. До блоков было больше вызовов с target / selector - я бы сказал, никогда не использовать это (используйте блоки вместо)

Другие вопросы по тегам