导致可怕的“巨大视图控制器”问题的一个原因是每个 View Controller 对其邻居的密切了解。
当我们尝试在我们的应用中重复使用 ViewController 以超过一个环境,或者通过不同的工作流程呈现 ViewController 时,我们开始在公共接口中添加标志属性,例如 @property (nonatomic) CurrentAppMode *howDidWeGetHere
。
当 ViewControllerA 想要呈现 ViewControllerB 时,ViewControllerA 必须知道如何确切地创建和配置 ViewControllerB。
这样做在一段时间内是有效的,但当我们想要引入 ViewControllerC,并在显示 ViewControllerB 之前按顺序放置它时,它会破裂?通常,我们需要从“A”代码中提取“B”代码,用创建和显示“C”的代码替换它。当然,我们必须对“C”进行修改,以提供创建和显示“B”的指令。
这种紧密耦合随着新的应用程序需求的引入而越来越导致头痛。
“Wireframes”一词是从VIPER 模式的描述中借用来的,尽管实现方式非常不同。
MFHWireframe
,可以按原样使用或子类化。-[UIViewController wireframe]
。wireframe
与您的视图控制器上的现有属性冲突,只需在您的头部文件中重新定义它,如下所示#define MFH_WIREFRAME_ACCESSOR_SELECTOR myBetterName
MFHWireframe
包裹一个 线程安全 的可变字典,其属性可以通过对象索引符号设置。// SomeViewController.m
- (void)viewDidLoad
{
// Create the wireframe.
MFHWireframe *wireframe = [[MFHWireframe alloc] init];
// Attach it to the current view controller.
// The view controller retains the wireframe, when the view controller is deallocated
// the wireframe will be released, too.
[wireframe attachToViewController:self];
}
// Some arbitrary event handler...
- (void)continueTapped:(id)sender
{
// Create your next view controller
NextViewController *nextVc = [[MyViewController alloc] init.....];
// Attach the current wireframe available via category extension at `[self wireframe]`
[self.wireframe attachToViewController:nextVc];
// Store arbitrary information in the wireframe.
wireframe[@"someKey"] = @"someValue";
// Show your new ViewController however you'd like:
[self.navigationController pushViewController:vc animated:YES];
}
// NextViewController.m
// Note that the wireframe created and attached `SomeViewController` is now available
// to use inside NextViewController, via `-[self wireframe]`
- (void)viewDidLoad
{
// Access information stored in the backing dictionary...
self.wireframe[@"someKey"]; // @"someValue"
}
Wireframe 子类是一个很好的地方,将决策和转换逻辑委派给之前紧密耦合的两个视图控制器
// MyWireframe.m
@interface MyWireframe : MFHWireframe
- (void)viewControllerDidRequestNextStep:(UIViewController*)viewController
@end
@implementation MyWireframe
- (void)viewControllerDidRequestNextStep:(UIViewController*)viewController
{
UIViewController *nextViewController;
if ([self[@"ShowIntro"] isEqualToNumber:@YES]) {
nextViewController = [[IntroViewController alloc] init...];
}
else {
nextViewController = [[AppViewController alloc] init...];
}
[self attachToViewController:nextVC];
[viewController.navigationController pushViewController:nextViewController animated:YES];
}
@end
// SomeViewController.m
- (void)continueTapped:(id)sender
{
[self.wireframe viewControllerDidRequestNextStep:self];
}
Wireframe 可以从一个 Wireframe 分支,这样分支 Wireframe 保留对父对象的弱引用。
如果客户端请求的key
尚未存储在后端字典中,则会递归地搜索父线框(s)直到找到存储在key
上的对象。
MFHWireframe *firstWireframe = [[MFHWireframe alloc] init];
MFHWireframe *childWireframe = [[MFHWireframe alloc] initBranchedWireframeFromWireframe:firstWireframe];
// Set something on the parent wireframe:
firstWireframe[@"ABC"] = @123;
// Retrieve this value via the child wireframe:
NSLog(@"%@", childWireframe[@"ABC"]); // @123;
// Set a different value on the child wireframe:
childWireframe[@"ABC"] = @456;
NSLog(@"%@", firstWireframe[@"ABC"]); // @123
NSLog(@"%@", childWireframe[@"ABC"]); // @456;
要运行示例项目;首先从示例目录克隆仓库,然后运行pod install
。
Matthew Holden, @MFHolden
MFHWireframes受MIT许可协议保护。有关更多信息,请参阅LICENSE文件。