Reputation: 3124
When using Objective-C
which is the preferred method to pass objects from the DataManager
to the Interactor
when utilising the VIPER
architectural pattern.
In particular use of Block Based Callbacks
vs. a DataManager Output Protocol
The Sample To Do App from the Original Mutual Mobile article on VIPER
uses Block Based Callbacks
like so
- (void)todoItemsBetweenStartDate:(NSDate *)startDate endDate:(NSDate *)endDate completionBlock:(void (^)(NSArray *todoItems))completionBlock;
Whereas this approach from Brigade Engineering
utilises an OutputProtocol
on the DataManager
[self.interactor foundUser:user];
Which is the better method and why?
Note: I know when using Swift, closures can make the callback method a lot cleaner. This question is with direct reference to Objective-C.
Upvotes: 4
Views: 675
Reputation: 248
I tend to prefer the use of an output protocol when possible as it makes testing easier. It is easier to use an output protocol when there is only one listener. If there are multiple listeners, it is easier to use a callback block, so that the object does not have to track the receiver for each request.
I find output protocols easier to test because you can call the listener directly. For example, a Presenter typically implements the output protocol of the Interactor. Let's say our Login Interactor output protocol has two methods:
- (void)didLogin
- (void)loginFailedWithError:(NSError*)error
When testing the Login Presenter, we will want to write tests for when login succeeds and when login fails. The test for successful login can directly call [presenter didLogin];
and the test for failure can directly call [presenter loginFailedWithError:badCredentialsError];
.
If, instead, we had used a callback block, the Login Interactor interface might look something like:
- (void)loginWithUsername:(NSString*)username password:(NSString*)password result:(void (^)(NSError* error))block;
When testing the presenter, to test the success case, you will need to stub the Interactor login method to return success, and then call a method on the Presenter that will force it to issue the login request to the Interactor.
[interactor willSucceed];
[presenter login];
This makes your test less clear as to the actual intent.
If you can design your DataManager API to support an output protocol, it will make testing easier. If not, I wouldn't worry about it, and just use a callback block.
Upvotes: 4
Reputation: 89192
This isn't cut and dry, but:
There are probably other heuristics you could use (e.g. delegation is better if there is probably an obvious object to implement the protocol and it would only need to implement it once).
You see both used in Apple's frameworks. Before blocks, there were more calls with target/selector -- I would say to never use that (use blocks instead)
Upvotes: 1