iOS关于如何让<界面切换逻辑>与<数据业务逻辑>解耦的探讨

来源:互联网 发布:php 整数保留2位小数 编辑:程序博客网 时间:2024/06/06 14:12

在各种问答社区里面游荡的时候,经常会有人问到类似于:

怎么在tableviewcell里面点击一个button让uitableviewcontroller切换到另外一个controller呢?

其实这个问题遇到的情况很多,其实还是View与Controller的代码解藕的问题。

这篇博客只是以这个问题的解决为目的:

最早几年前接触iOS的时候用了一个当时很火的库:Three20 from facebook。但是随着编程思维的转变,发现这样的库有几个不好的地方:

1. 太过于重量级,什么功能都有

2. 自定义比较麻烦

3. 库内部的模块代码耦合太严重

所以我们后来花了很大的力气,把这个库完全去除。后来我们搭建iOS工程的基本是不会选择大型库的。典型的一个例子:AFNetworking VSMKNetworkKit 这个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 : JKSingletonObjectJK_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] initWithNibName: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。

0 0
原创粉丝点击