jjzjj

iOS之VC和V减负操作

江湖闹士 2023-03-28 原文

总结一下目前使用的架构
主要分为VC Model View ViewModel Logic

Logic

在MVC模式下,我们一般都是将网络请求等操作都放在V控制器中,会让控制器中代码量很大,查找代码挺困难,现在把网络请求操作放到Logic中,每一个业务模块,可以创建一个Logic类,继承于NSObject,然后将外部需要的网络请求事件(包括进入页面时的数据请求和用户交互所需的请求)提供接口,内部处理请求事件,然后通过回调或者代理的方式将数据提供到控制器

logic类中,可以提供实例方法或者类方法都可以,怎么方便怎么来。如果用到多类型,多使用枚举来处理,比如网络请求的结果

//请求状态类型
typedef NS_ENUM(NSInteger,SJRequestStatus){
    SJRequestStatusExecuting = 0,  //请求进行中
    SJRequestStatusFail,           //请求失败
    SJRequestStatusEnd,            //请求成功,但是结果非预期
    SJRequestStatusSuccess,        //请求成功,结果等于预期
};

除了网络请求的操作外,Logic中还可以做处理一些业务上的逻辑,比如:是否实名认证过,我们通过Logic的一个对外接口直接就可以获取结果,将逻辑放在内部,就比较好了。其实整体看来Logic像是一个工具类了,将原来VC中冗余的代码逻辑都放在了Logic中,这样的话VC就精简了不少,这样看的话Logic的作用就是简化控制器VC的代码。

ViewModel

我们给view赋值完(cell.mode = model)然后就是view内部自己去渲染,有时候model提供的值其实不是可以直接用的,需要自己去判断逻辑,处理计算,然后才能展示。MVC模式下,这些判断计算的逻辑都在view中进行,这样的话view中的代码量也是起来了。这时候如果把这写逻辑拿出来处理,提供给view的是直接可以给控件渲染的数据那就好了,viewModel就是做这些事的。

值得注意的是:block要注意避免循环引用问题

@interface SJCommentCellViewModel : NSObject

@property (nonatomic, strong) SJcommentModel *model;

- (SJCommentCellViewModel* (^)(SJcommentModel *))configModel;
//一级评论数据
- (SJCommentCellViewModel*)configProfile:(void(^)(NSString *,BOOL))profile
                                                     name:(void(^)(NSString *))name
                                                     date:(void(^)(NSString *))date
                                                  content:(void(^)(NSMutableAttributedString *))content;
@end
@implementation SJCommentCellViewModel
- (instancetype)init {
    if (self = [super init]) {
        
    }
    return self;
}

//给当前viewmodel的model设值,供其他方法使用全局model作准备
- (SJCommentCellViewModel* (^)(SJcommentModel *))configModel {
    @weakify(self);
    return ^(SJcommentModel *model){
        @strongify(self);
        self.model = model;
        return self;
    };
}

//一级评论数据
- (SJCommentCellViewModel*)configProfile:(void(^)(NSString *,BOOL))profile
                                                     name:(void(^)(NSAttributedString *))name
                                                     date:(void(^)(NSString *))date
                                                  content:(void(^)(NSMutableAttributedString *))content{
    @weakify(self);
    if (profile) {
        @strongify(self);
        BOOL isGov = self.model.type == JYMomentsUserGov;
        profile(self.model.headImageUrl,isGov);
    }
    if (name) {
        @strongify(self);
        NSAttributedString *attributedText = [self configWithCommentNickName:self.model.nickName];
        name(attributedText);
    }
    if (date) {
        @strongify(self);
        NSString *timeDes = kSafeStr(self.model.commentTimeDes);
        date(timeDes);
    }
    if (content) {
        @strongify(self)
        //富文本处理
        content([self contentAttributedStringWithModel:self.model]);
    }
    return self;
}

以下几种情况:
1、需要进行进一步判断的
2、需要获取到model层级比较深的属性
3、需要对数据进一步计算或者处理的
可以看到我们拿到model后,里面数据有的需要富文本进一步处理,这些操作都放在viewmodel中处理好了再通过block回调回去,使用代码如下:

//view中给控件赋值渲染时使用
- (void)configViewWithModel:(SJcommentModel *)model{
@weakify(self);
    [self.viewModel.configModel(model) configProfile:^(NSString *profile, BOOL isGov) {
        [self.headImageView_1 configProfileImage:profile isGov:isGov];
    } name:^(NSAttributedString *name) {
        self.nameLab_1.attributedText = name;
    } date:^(NSString *date) {
        self.timeLab_1.text = date;
    } content:^(NSMutableAttributedString *content) {
        self.contentLab_1.attributedText = content;
    }];
}

这样的话view层就特别干净整洁,但是可以看出view还是对model有依赖的,并没有解耦

总结:Logic和ViewModel的作用完全是为了精简VC和View的代码量,起到减负的作用,并没有起到解耦合的作用,但是以我的理解,在一个业务中,本身业务内部耦合性就挺高的,想拆分开也不可能,通过这种方法单纯把逻辑拿出来,可以方便查找问题,帮助还是挺大的,代码看起来就很舒服

有关iOS之VC和V减负操作的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  4. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  5. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  6. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  7. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  8. ruby - 在 Ruby 中是否有一种惯用的方法来操作 2 个数组? - 2

    a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],

  9. ruby-on-rails - 如何让 Rails View 返回其关联的操作名称? - 2

    我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam

  10. Postman测试简单操作 - 2

    1、接口请求基本操作1.1例子tips在view的选项可以zoomin调整窗口字帖大小。1、创建一个测试的workspace,并命名为test2、test后面新增一个addrequest3、选择发送GET,URL为一个开源的https://api.apiopen.top/api/sentences获取每日一句4、点击send查看内容Tips:如果提示出现Error:tunnelingsocketcouldnotbeestablished,statusCode=407错误,参照以下解决办法)关于tunnelingsocketcouldnotbeestablished,cause=getaddri

随机推荐