美文网首页
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