VIPER 架构分析

https://stackoverflow.com/questions/38510318/ios-using-viper-with-uitableview
https://objccn.io/issue-13-5/

目的:每一个部分容易被识别,带有特定而明显的目的。写出更好的容易测试的代码。创建简明架构:将逻辑结构分为不同的责任曾,使得它更容易隔离依赖项,也更容易测试边界交互。

  • 交互器:一个独立功能的用例,这里面包含一个 initWithManager:(id)manager和待处理的object,然后一个方法如findUpcomingItems返回数据到interactor的output中

  • 实体: interactor处理和返回实体,是一个普通的Object, 如果有CoreData,保存在数据层之后,交互器里面不与NSManagObject协同工作

  • 展示器:也是一个Object,他和wireframe互相持有。他实际上处理交互器的交互,并交给wireframe来显示或者交给interface来处理。一个ViewController实际上持有一个presenter.

  • 视图View:Interface,是一个抽象协议,这个interface作为一个protocol, 被展示器展示出来。一个ViewController会实现这个协议中的内容

  • 路由Routing:路由由于wireframe和展示器负责,wireframe从一开始从appdelegate拿到window之后就开始负责viewController的展示了。uiViewController的TransitioningDelegate也在里面定义。一个wireframe可以增加另外一个wireframe如listwireframe可以有一个addwireframe的属性。

好麻烦 ><

  • 联网交给交互器来完成联网操作,但是真正的联网是会找一个networkmanager
  • 交互器也不知道如何持久化,他会调用一个dataManager来实现
  • 最好不要使用storyboard的segues,这样就会与routing的职责和行为出现冲突

ViewController appear的时候,调用了self.eventHandler(presenter)的 updateView
presenter 调用了Interactor 的findUpcomingItems
[Interactor findUpcomingItems]; 调用manager,将结果返回到output中(Presenter
[Presenter foundUpcomingItems];//判断逻辑,看调用VC的哪个方法
[ViewController showNoContentMessage]

点击之后的操作

  • 点击之后调用[presenter 的方法]
  • presenter中有router, router来负责管理接下来的路径

OCMock以及测试

https://objccn.io/issue-15-2/
http://ocmock.org/introduction/

  • XCTFail(“not implemented”)断言强制失败
  • setUp, tearDown
  • TDD应该先写测试.
  • XCTAssertNotNil来保证某一个东西是否存在
  • Mock 模拟对象,stub桩程序
  • stub: 人为的指定一个结果,测试某一个操邹,人为的让某一个方法返回我们事先规定好的值,叫stub。stub只是简单的方法替换,不涉及对象。
  • mock:mock行为产生一个新的对象。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)testDisplaysTweetsRetrievedFromConnection
{
Controller *controller = [[[Controller alloc] init] autorelease];

id mockConnection = OCMClassMock([TwitterConnection class]);
controller.connection = mockConnection;

Tweet *testTweet = /* create a tweet somehow */;
NSArray *tweetArray = [NSArray arrayWithObject:testTweet];
OCMStub([mockConnection fetchTweets]).andReturn(tweetArray);

[controller updateTweetView];

OCMVerify([mockView addTweet:[OCMArg any]]);//表示确定mockView调用了某一个方法

}

首先mock了一个class,然后伪造了一个数据stub到某一个方法里面,然后调用了updateTweetView方法

依赖注入

  • 一种是initWith…(Constroctor Injection) prefere this
  • 一种是暴露一个property出来 (Setter Injection)