iOS关于如何让<界面切换逻辑>与<数据业务逻辑>解耦的探讨
2014-08-22 11:03
549 查看
在各种问答社区里面游荡的时候,经常会有人问到类似于:
怎么在tableviewcell里面点击一个button让uitableviewcontroller切换到另外一个controller呢?
其实这个问题遇到的情况很多,其实还是View与Controller的代码解藕的问题。
这篇博客只是以这个问题的解决为目的:
最早几年前接触iOS的时候用了一个当时很火的库:Three20 from facebook。但是随着编程思维的转变,发现这样的库有几个不好的地方:
1. 太过于重量级,什么功能都有
2. 自定义比较麻烦
3. 库内部的模块代码耦合太严重
所以我们后来花了很大的力气,把这个库完全去除。后来我们搭建iOS工程的基本是不会选择大型库的。典型的一个例子:AFNetworking VS
MKNetworkKit 这个2个库我们选择的是MKNetworkKit,很显然后者更轻量级。AFNetworking做了很多其他的工作,比如:图片异步加载,但是显然这些工作会有更优秀的第三方库类似于SDWebImage 来完成。
再回到一开始的问题,这也是一个解藕的问题,那么我是怎么做的呢?解决方法来源于Three20的TTNavigator,我把他从Three20框架中剥离了出来,并同时优化了一下(不再是 url-base-navigation)。
直接上代码了:
JKNavigator.h
JKNavigator.m
#import "JKNavigator.h"
#import "JKViewController.h"
@interface JKNavigator ()
@property (nonatomic, strong) Class navigationSubclass;
@end
@implementation JKNavigator
@synthesize navigationSubclass = _navigationSubclass;
JK_SINGLETON_INSTANCE_METHOD_IMPL(JKNavigator)
#pragma mark - Getter & Setter
- (Class)navigationSubclass
{
if (!_navigationSubclass) {
_navigationSubclass = [UINavigationController class];
}
return _navigationSubclass;
}
- (void)setNavigationSubclass:(Class)navigationSubclass
{
if ([navigationSubclass isSubclassOfClass:[UINavigationController class]]) {
_navigationSubclass = navigationSubclass;
} else {
@throw [NSException exceptionWithName:@"Incorrect Class" reason:@"You can only set UINavigationController subclass here." userInfo:@{}];
}
}
- (UIWindow *)window
{
return [UIApplication sharedApplication].keyWindow;
}
- (UIViewController *)rootViewController
{
return self.window.rootViewController;
}
- (UINavigationController *)topNavigationController
{
UINavigationController *root = (UINavigationController *)self.rootViewController;
while (root) {
UINavigationController *child = (UINavigationController *)root.presentedViewController;
if (child && [child isKindOfClass:[UINavigationController class]]) {
root = child;
} else {
return root;
}
}
return nil;
}
#pragma mark - Remove all.
- (void)removeAllViewControllers
{
UINavigationController *rootNavigator = (UINavigationController *)self.rootViewController;
UINavigationController *root = (UINavigationController *)self.rootViewController;
while (root) {
if (root && [root isKindOfClass:[UINavigationController class]]) {
[root dismissViewControllerAnimated:NO completion:NULL];
}
root = (UINavigationController *)root.presentedViewController;;
}
[rootNavigator popToRootViewControllerAnimated:NO];
}
#pragma mark - Private methods
- (UIViewController *)pushViewController:(NSString *)classString
withNib:(BOOL)witNib
withQuery:(id)query
animated:(BOOL)animated
{
return [self showViewControllerWithAction:@"Push"
classString:classString
withNib:witNib
withQuery:query
animated:animated
completion:NULL];
}
- (UIViewController *)presentViewController:(NSString *)classString
withNib:(BOOL)witNib
withQuery:(id)query
animated:(BOOL)animated
completion:(void(^)(void))completion
{
return [self showViewControllerWithAction:@"Present"
classString:classString
withNib:witNib
withQuery:query
animated:animated
completion:completion];
}
- (UIViewController *)showViewControllerWithAction:(NSString *)action
classString:(NSString *)classString
withNib:(BOOL)witNib
withQuery:(id)query
animated:(BOOL)animated
completion:(void(^)(void))completion
{
UIViewController *controller = nil;
UINavigationController *topNavigationController = [self topNavigationController];
// Generate UIViewController from classString.
Class class = NSClassFromString(classString);
if ([class isSubclassOfClass:[JKViewController class]]) {
controller = witNib ? [[class alloc] initWithNibAndQuery:query] : [[class alloc] initWithQuery:query];
} else if ([class isSubclassOfClass:[UIViewController class]]) {
controller = witNib ? [[class alloc] initWit
9e19
hNibName:classString bundle:nil] : [[class alloc] init];
}
// Show controller.
if (controller && topNavigationController) {
if ([action isEqualToString:@"Push"]) {
[topNavigationController pushViewController:controller animated:animated];
} else if ([action isEqualToString:@"Present"]) {
if ([controller isKindOfClass:[UINavigationController class]]) {
[topNavigationController presentViewController:controller animated:animated completion:completion];
} else {
UINavigationController *navigation = [[self.navigationSubclass alloc] initWithRootViewController:controller];
navigation.view.backgroundColor = self.navigationControllerBackgroundColor;
[topNavigationController presentViewController:navigation animated:animated completion:completion];
}
}
}
return controller;
}
#pragma mark - Push methods
- (void)registerNavigationSubclass:(Class)navigationSubclass;
{
self.navigationSubclass = navigationSubclass;
}
#pragma mark
- (UIViewController *)pushViewController:(NSString *)classString animated:(BOOL)animated
{
return [self pushViewController:classString withNib:NO withQuery:nil animated:animated];
}
- (UIViewController *)pushViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self pushViewController:classString withNib:NO withQuery:query animated:animated];
}
- (UIViewController *)pushNibViewController:(NSString *)classString animated:(BOOL)animated
{
return [self pushViewController:classString withNib:YES withQuery:nil animated:animated];
}
- (UIViewController *)pushNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self pushViewController:classString withNib:YES withQuery:query animated:animated];
}
#pragma mark
- (UIViewController *)presentViewController:(NSString *)classString animated:(BOOL)animated
{
return [self presentViewController:classString withNib:NO withQuery:nil animated:animated completion:NULL];
}
- (UIViewController *)presentViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self presentViewController:classString withNib:NO withQuery:query animated:animated completion:NULL];
}
- (UIViewController *)presentViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated completion:(void(^)(void))completion
{
return [self presentViewController:classString withNib:NO withQuery:query animated:animated completion:completion];
}
- (UIViewController *)presentNibViewController:(NSString *)classString animated:(BOOL)animated
{
return [self presentViewController:classString withNib:YES withQuery:nil animated:animated completion:NULL];
}
- (UIViewController *)presentNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self presentViewController:classString withNib:YES withQuery:query animated:animated completion:NULL];
}
- (UIViewController *)presentNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated completion:(void(^)(void))completion
{
return [self presentViewController:classString withNib:YES withQuery:query animated:animated completion:completion];
}
@end
当然其中还部分牵扯到了其他的class,可以根据你的需求去除。JKNavigator是一个singleton object。使用时异常简单:
[[JKNavigator instance] pushViewController:@"YourViewControllerClassString" animated:YES];
[[JKNavigator instance] pushNibViewController:@"YourViewControllerClassString" animated:YES];
不需要包含任何头文件,在任何地方都可以进行push操作。极大程序上解藕了View和Controller。
怎么在tableviewcell里面点击一个button让uitableviewcontroller切换到另外一个controller呢?
其实这个问题遇到的情况很多,其实还是View与Controller的代码解藕的问题。
这篇博客只是以这个问题的解决为目的:
最早几年前接触iOS的时候用了一个当时很火的库:Three20 from facebook。但是随着编程思维的转变,发现这样的库有几个不好的地方:
1. 太过于重量级,什么功能都有
2. 自定义比较麻烦
3. 库内部的模块代码耦合太严重
所以我们后来花了很大的力气,把这个库完全去除。后来我们搭建iOS工程的基本是不会选择大型库的。典型的一个例子:AFNetworking VS
MKNetworkKit 这个2个库我们选择的是MKNetworkKit,很显然后者更轻量级。AFNetworking做了很多其他的工作,比如:图片异步加载,但是显然这些工作会有更优秀的第三方库类似于SDWebImage 来完成。
再回到一开始的问题,这也是一个解藕的问题,那么我是怎么做的呢?解决方法来源于Three20的TTNavigator,我把他从Three20框架中剥离了出来,并同时优化了一下(不再是 url-base-navigation)。
直接上代码了:
JKNavigator.h
#import <Foundation/Foundation.h> /************************************************************************ * Dependencies: JKSingletonObject, JKViewController. * Based on: TTNavigator. ************************************************************************/ #import "JKSingletonObject.h" @interface JKNavigator : JKSingletonObject JK_SINGLETON_INSTANCE_METHOD_INTERFACE(JKNavigator) /** * The window that contains the view controller hierarchy. */ @property (nonatomic, readonly) UIWindow *window; /** * The controller that is at the root of the view controller hierarchy. */ @property (nonatomic, readonly) UIViewController* rootViewController; @property (nonatomic, readonly) UINavigationController* topNavigationController; /** * Removes all view controllers from the window and releases them. */ - (void)removeAllViewControllers; /** * Register class. */ - (void)registerNavigationSubclass:(Class)navigationSubclass; /*! * Set navigaiton controller view background color. */ @property (nonatomic, strong) UIColor *navigationControllerBackgroundColor; /** * Push view controller in global navigator. * lightweight API for [Push & Present ViewController]. * I think it's more suitable than Url-based in Three20 for us. Here are some reasons: * => 1. APIs look like official APIs. * => 2. Easy to know the Class name without importing the header. * => 3. More controllable for us. */ - (UIViewController *)pushViewController:(NSString *)classString animated:(BOOL)animated; - (UIViewController *)pushViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated; - (UIViewController *)pushNibViewController:(NSString *)classString animated:(BOOL)animated; - (UIViewController *)pushNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated; - (UIViewController *)presentViewController:(NSString *)classString animated:(BOOL)animated; - (UIViewController *)presentViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated; - (UIViewController *)presentViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated completion:(void(^)(void))completion; - (UIViewController *)presentNibViewController:(NSString *)classString animated:(BOOL)animated; - (UIViewController *)presentNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated; - (UIViewController *)presentNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated completion:(void(^)(void))completion; @end
JKNavigator.m
#import "JKNavigator.h"
#import "JKViewController.h"
@interface JKNavigator ()
@property (nonatomic, strong) Class navigationSubclass;
@end
@implementation JKNavigator
@synthesize navigationSubclass = _navigationSubclass;
JK_SINGLETON_INSTANCE_METHOD_IMPL(JKNavigator)
#pragma mark - Getter & Setter
- (Class)navigationSubclass
{
if (!_navigationSubclass) {
_navigationSubclass = [UINavigationController class];
}
return _navigationSubclass;
}
- (void)setNavigationSubclass:(Class)navigationSubclass
{
if ([navigationSubclass isSubclassOfClass:[UINavigationController class]]) {
_navigationSubclass = navigationSubclass;
} else {
@throw [NSException exceptionWithName:@"Incorrect Class" reason:@"You can only set UINavigationController subclass here." userInfo:@{}];
}
}
- (UIWindow *)window
{
return [UIApplication sharedApplication].keyWindow;
}
- (UIViewController *)rootViewController
{
return self.window.rootViewController;
}
- (UINavigationController *)topNavigationController
{
UINavigationController *root = (UINavigationController *)self.rootViewController;
while (root) {
UINavigationController *child = (UINavigationController *)root.presentedViewController;
if (child && [child isKindOfClass:[UINavigationController class]]) {
root = child;
} else {
return root;
}
}
return nil;
}
#pragma mark - Remove all.
- (void)removeAllViewControllers
{
UINavigationController *rootNavigator = (UINavigationController *)self.rootViewController;
UINavigationController *root = (UINavigationController *)self.rootViewController;
while (root) {
if (root && [root isKindOfClass:[UINavigationController class]]) {
[root dismissViewControllerAnimated:NO completion:NULL];
}
root = (UINavigationController *)root.presentedViewController;;
}
[rootNavigator popToRootViewControllerAnimated:NO];
}
#pragma mark - Private methods
- (UIViewController *)pushViewController:(NSString *)classString
withNib:(BOOL)witNib
withQuery:(id)query
animated:(BOOL)animated
{
return [self showViewControllerWithAction:@"Push"
classString:classString
withNib:witNib
withQuery:query
animated:animated
completion:NULL];
}
- (UIViewController *)presentViewController:(NSString *)classString
withNib:(BOOL)witNib
withQuery:(id)query
animated:(BOOL)animated
completion:(void(^)(void))completion
{
return [self showViewControllerWithAction:@"Present"
classString:classString
withNib:witNib
withQuery:query
animated:animated
completion:completion];
}
- (UIViewController *)showViewControllerWithAction:(NSString *)action
classString:(NSString *)classString
withNib:(BOOL)witNib
withQuery:(id)query
animated:(BOOL)animated
completion:(void(^)(void))completion
{
UIViewController *controller = nil;
UINavigationController *topNavigationController = [self topNavigationController];
// Generate UIViewController from classString.
Class class = NSClassFromString(classString);
if ([class isSubclassOfClass:[JKViewController class]]) {
controller = witNib ? [[class alloc] initWithNibAndQuery:query] : [[class alloc] initWithQuery:query];
} else if ([class isSubclassOfClass:[UIViewController class]]) {
controller = witNib ? [[class alloc] initWit
9e19
hNibName:classString bundle:nil] : [[class alloc] init];
}
// Show controller.
if (controller && topNavigationController) {
if ([action isEqualToString:@"Push"]) {
[topNavigationController pushViewController:controller animated:animated];
} else if ([action isEqualToString:@"Present"]) {
if ([controller isKindOfClass:[UINavigationController class]]) {
[topNavigationController presentViewController:controller animated:animated completion:completion];
} else {
UINavigationController *navigation = [[self.navigationSubclass alloc] initWithRootViewController:controller];
navigation.view.backgroundColor = self.navigationControllerBackgroundColor;
[topNavigationController presentViewController:navigation animated:animated completion:completion];
}
}
}
return controller;
}
#pragma mark - Push methods
- (void)registerNavigationSubclass:(Class)navigationSubclass;
{
self.navigationSubclass = navigationSubclass;
}
#pragma mark
- (UIViewController *)pushViewController:(NSString *)classString animated:(BOOL)animated
{
return [self pushViewController:classString withNib:NO withQuery:nil animated:animated];
}
- (UIViewController *)pushViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self pushViewController:classString withNib:NO withQuery:query animated:animated];
}
- (UIViewController *)pushNibViewController:(NSString *)classString animated:(BOOL)animated
{
return [self pushViewController:classString withNib:YES withQuery:nil animated:animated];
}
- (UIViewController *)pushNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self pushViewController:classString withNib:YES withQuery:query animated:animated];
}
#pragma mark
- (UIViewController *)presentViewController:(NSString *)classString animated:(BOOL)animated
{
return [self presentViewController:classString withNib:NO withQuery:nil animated:animated completion:NULL];
}
- (UIViewController *)presentViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self presentViewController:classString withNib:NO withQuery:query animated:animated completion:NULL];
}
- (UIViewController *)presentViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated completion:(void(^)(void))completion
{
return [self presentViewController:classString withNib:NO withQuery:query animated:animated completion:completion];
}
- (UIViewController *)presentNibViewController:(NSString *)classString animated:(BOOL)animated
{
return [self presentViewController:classString withNib:YES withQuery:nil animated:animated completion:NULL];
}
- (UIViewController *)presentNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated
{
return [self presentViewController:classString withNib:YES withQuery:query animated:animated completion:NULL];
}
- (UIViewController *)presentNibViewController:(NSString *)classString withQuery:(id)query animated:(BOOL)animated completion:(void(^)(void))completion
{
return [self presentViewController:classString withNib:YES withQuery:query animated:animated completion:completion];
}
@end
当然其中还部分牵扯到了其他的class,可以根据你的需求去除。JKNavigator是一个singleton object。使用时异常简单:
[[JKNavigator instance] pushViewController:@"YourViewControllerClassString" animated:YES];
[[JKNavigator instance] pushNibViewController:@"YourViewControllerClassString" animated:YES];
不需要包含任何头文件,在任何地方都可以进行push操作。极大程序上解藕了View和Controller。
相关文章推荐
- <java> <JTable> 关于设置JTable导入数据后自动排序-小记
- <如何实现1080P延迟低于500ms的实时超清直播传输技术> <关于直播,所有的技术细节都在这里了>
- lae界面开发工具入门之介绍十三--<如何获取数据?>
- lae界面开发工具入门之介绍十二--<iOS系统如何编译打包?>
- <iOS>关于子线程和block中操作主线程界面的控件讨论
- 以<asp:Button>为例说明<asp:Button>如何携带数据传递到后台
- 关于XML <如何操作XML>
- Linux界面切换:图形界面<——>字符界面
- python如何提取某一个固定的字符之间的数据如<img src= >" 内容"
- 业务逻辑>数据层>SqlDataSource>sql的输入参数>控件参数>System.Web.UI.WebControls.GridView.SelectedValue
- 如何使用 BindingSource 绑定 ListBox,同时解决绑定 List<T> 后修改数据源不能同时刷新界面显示的问题
- 小白学数据分析-----> 有关于流失分析的探讨
- 关于servlet服务端接收客户端发送的List<?>数据的问题
- 关于<object>与<embed>的区别
- <关于数据类型的一些看法---C语言版本>
- 如何进行界面和业务逻辑分开的原型化开发
- 如何将一个List<Map<String,String>>类型的集合数据转换成json格式输出
- 如何在程序中部署界面和业务逻辑.
- 关于JavaScript针对<ul><li>的一些操作
- 业务逻辑>数据层>ObjectDataSource>数据源分页机制