一个用于将多个 UIViewControllers
链接在一起以获得最终/单个值的简单 DSL
尽可能的情况下,我总是试图创建我的 UIViewControllers
,使它们与其他任何非视觉组件具有相同的模块化。它们应该能够插入到一个 UIViewControllers
的 '流' 中,并在最后得到一些结果。换句话说,我的 UIViewControllers
通常很愚蠢,它们可能会接受一些输入并有一些输出,但它们对功能之外的事情一无所知。
设想我们正在创建一个小型联系人应用程序,该应用的 '流' 可能是这样的
使用 IKAsyncViewController
,这种逻辑可以抽象化,并写成以下形式
-(void)callContact:(UINavigationController *)navController animate:(BOOL)animate {
navController
.push(^{
return [ContactListViewController new];
}, animate)
.then(^(User *user){
return [PhoneNumberViewController newWithUser:user];
}, animate)
.finally(^(NSString *phoneNumber) {
NSString *phoneNumberString = [NSString stringWithFormat:@"tel://%@", phoneNumber];
NSURL *url = [NSURL URLWithString:phoneNumberString];
[[UIApplication sharedApplication] openURL:url];
});
return YES;
}
设置一个 UIViewController 来支持此流程很简单
.h
#import <IKAsyncViewControllers/IKAsyncViewController.h>
@interface ViewController : UIViewController <IKAsyncViewController>
@end
.m
#import "IKAsyncViewControllerOutput.h"
@interface ViewController ()
@property (nonatomic, strong) IKAsyncViewControllerOutput *output;
@end
@implementation ViewController
-(void)useOutput:(IKAsyncViewControllerOutput *)output {
self.output = output;
}
-(IBAction)actionTriggered:(id)sender {
[self.output output:<output_value>];
}
@end
使用 UINavigationController
类的方法来启动 IKAsyncViewController
链很容易。给定创建要显示的第一个视图控制器的方法
-(UIViewController<IKAsyncViewController> *)firstViewController { ... }
您可以使用 root
块将其设置为根视图控制器
-(void)startChain:(UINavigationController *)navController animate:(BOOL)animate {
navController.root(^{ return [self firstViewController]; }, animate);
}
或者您可以使用 push
块将其推送到现有的堆栈中
-(void)startChain:(UINavigationController *)navController animate:(BOOL)animate {
navController.push(^{ return [self firstViewController]; }, animate);
}
从一个 IKAsyncViewController
解析值到下一个也很简单。给定创建一个接收某些输入并产生某些输出的 IKAsyncViewController
的方法
-(UIViewController<IKAsyncViewController> *)anotherViewController:(id)input { ... }
-(UIViewController<IKAsyncViewController> *)andAnotherViewController:(id)input { ... }
您可以使用 then
块
-(void)startChain:(UINavigationController *)navController animate:(BOOL)animate {
navController.root(^{ return [self firstViewController]; }, animate)
.then(^(id output) { return [self anotherViewController:output]; }, animate)
.then(^(id output) { return [self andAnotherViewController:output]; }, animate);
}
或者使用 thenIf
块来有条件地显示一个 IKAsyncViewController
。如果谓词为 NO
,则将在链中跳过 IKAsyncViewController
-(void)startChain:(UINavigationController *)navController {
navController.root(^{ return [self firstViewController]; })
.thenIf([self shouldShowAnother], ^(id output) { return [self anotherViewController:output]; }, animate)
.then(^(id output) { return [self andAnotherViewController:output]; }, animate);
}
-(BOOL)shouldShowAnother { ... }
最终的想法是从一系列 IKAsyncViewController
中获得一些最终值,这可以通过 finally
块来实现
-(void)startChain:(UINavigationController *)navController {
navController.root(^{ return [self firstViewController]; })
.thenIf([self shouldShowAnother], ^(id output) { return [self anotherViewController:output]; }, animate)
.then(^(id output) { return [self andAnotherViewController:output]; }, animate)
.finally(^(id finalValue) {
//.. do something with finalValue
});
}
-(BOOL)shouldShowAnother { ... }
IKAsyncViewControllers
是一个简单而巧妙的 Domain Specific Language (DSL),可以帮助您思考如何使您的 UIViewControllers 更模块化。当您有一组定义明确的 UIViewControllers,可以将它们串联起来以获得某些输出时,这是一个非常好的工具。
IKAsyncViewControllers
不是 storyboards 的替代品,虽然它可以用于复杂的/多分支导航,但这并不意味着它总是适合这个工作。仔细考虑一下,IKAsyncViewControllers
是否适合您的应用程序。
或通过手动将 IKEvents
子文件夹中的源文件添加到您的项目中
欢迎提出 Pull Requests!
如果您在项目中使用这个工具,我很想听到您的反馈!
我通常在 iOS Developers 上。您应该去看看它们!