美文网首页
iOS 开发中的 Self-Manager 模式

iOS 开发中的 Self-Manager 模式

作者: L4H | 来源:发表于2016-03-26 17:20 被阅读0次

    给某个视图更大的权力,让它自己负责处理自己的事件

    有一个例子:负责展示头像的视图

    它的职责包括:

    • 1、通过传入的 URL,加载并展示头像图片
    • 2、显示一些附属信息,比如大V的标志
    • 3、将用户点击头像的事件传递给外层的 View Controller 跳转到用户信息页面

    代码是这样的:

    @interface FDAvatarView : UIView
    // 假设 VIPInfo 是某个 Entity
    - (void)configureWithAvatarURL:(NSURL *)URL VIPInfo:(id)info tapped:(void (^)(void))block;
    @end
    

    使用这个控件的人只要调用该方法传入参数就ok。但此时会有个问题:

    • 1、上面的例子,UITableViewCell会调用这个方法,但是cell并不知道自己的ViewController是谁,于是乎事件得往上传,直到能找到自己的navigation,然后跳转到下一个界面。
    • 2、这个FDAvatarView出现在多个界面,而且行为一致的话,这样多个界面就都要处理该事件。还会多出来只是向上一层传递事件的中间人

    为解决这个问题,就需要给这个 View 放权,让其自己 Handle 自己的事件,也就是 Self-Managed,为了不破坏 View 的纯洁性,比较好的实践是在 Category 中实现:

    @interface FDAvatarView (FDAvatarViewSelfManager)
    - (void)selfManagedConfigureWithAvatarURL:(NSURL *)URL VIPInfo:(id)info uid:(NSString *)uid;
    @end
    

    实现:

    @implementation FDAvatarView (FDAvatarViewSelfManager)
    // 为后一个页面的创建增加了个 UID 参数
    - (void)selfManagedConfigureWithAvatarURL:(NSURL *)URL VIPInfo:(id)info UID:(NSString *)UID {
        [self configureWithAvatarURL:URL VIPInfo:info tapped:^{
            // 假设 App 结构是 Root -> TabBar -> Navigation -> ViewController
            UITabBarController *tabBarControler = (id)[UIApplication.sharedApplication.delegate.window.rootViewController;
            UINavigationController *navigationController = tabBarControler.selectedViewController;
            // 创建用户信息 View Controller
            FDUserProfileViewController *profileViewController = [FDUserProfileViewController viewControllerWithUID:UID];
            [navigationController pushViewController:profileViewController animated:YES];
        }];
    }
    @end
    

    这里用到了类似 AOP(面向对象) 的思路,添加了对 App 层级的耦合(调用者只要调用了该方法就会直接跳转到用户界面),如果觉得这样的耦合方式不妥的话,也可以封装个全局方法去取到当前顶层的 Navigation Controller
    这样,FDAvatarView 的调用者只需要配置入参,其余的它自己全能搞定了,即使 App 内很多处出现头像,逻辑代码也只有一份。

    接下来再看一个例子:


    这个点赞的按钮功能上有几个职责:

    显示已有的点赞数
    点击按钮后执行一个小动画,点赞数 +1,同时发送网络请求。
    若已经点赞,点击执行反向操作
    若网络请求发送失败,则回退成点击前的状态

    这个控件的 代码 可以设计成这样:

    @interface FDLikeButton : UIButton
    - (void)configureLikeStatus:(BOOL)likeOrNot count:(NSInteger)count animated:(BOOL)animated;
    @end
    

    因为继承自 UIButton,所以外部可以直接设置其 action,就不增加 tappedHandler 的参数了。外部直接在点击事件中需要调用这个配置方法,播放点赞动画,紧接着发送一个网络请求,若网络请求失败,可以再次调用这个 API 的无动画版本回滚状态。

    有个问题,像上面的例子一样,网络请求事件处理逻辑相同,但代码却分部在各个页面中,于是给这个 View 增加 Self-Managed 模式的 Category

    @interface FDLikeButton (FDLikeButtonSelfManager)
    - (void)selfManagedConfigureWithLikeStatus:(BOOL)likeOrNot count:(NSInteger)count;
    @end
    
    @implementation FDLikeButton (FDLikeButtonSelfManager)
    - (void)selfManagedConfigureWithLikeStatus:(BOOL)likeOrNot count:(NSInteger)count {
        [self configureLikeStatus:likeOrNot count:count animated:NO];
        [self addTarget:self action:@selector(likeButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    }
    - (void)likeButtonTapped:(id)sender {
        // +1 or -1 with animation
        // Network request ^(NSError *error) {
        //     if (error) {
        //         rollback
        //     }
        // }
    }
    @end
    

    设计上,Self-Manager 模式并没有破坏原有的 MVC 结构,上面两个例子中的 View 依然可以不耦合具体业务逻辑的单拿出来用。使用 Category 的方式把应该写在 ViewController 中的代码移动到 View 的文件中,让功能更加的内聚

    程序的复杂度并不会因哪种酷炫的设计模式所减少,能做到的只是对复杂度的切分控制,即:

    • 1、让一大坨恶心的代码变成几小坨不那么恶心的代码。
    • 2、让恶心的代码只在一个地方恶心

    来源于 http://blog.sunnyxx.com/ 博客。

    相关文章

      网友评论

          本文标题:iOS 开发中的 Self-Manager 模式

          本文链接:https://www.haomeiwen.com/subject/srvdlttx.html