博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS for MVC模式
阅读量:4086 次
发布时间:2019-05-25

本文共 5539 字,大约阅读时间需要 18 分钟。

什么是MVC?

MVC逻辑示意图

我们接下来通过MVC模式要实现的界面:

文件夹结构:

自定义视图AppView.xib示意图:

控制层:

"ViewController.h"

////  ViewController.m////  Created by Long.//  Copyright © 2016年 LongChuang. All rights reserved.//#import "ViewController.h"#import "AppData.h"#import "AppView.h"@interface ViewController ()@end@implementation ViewController{    // 用于接收loadAppData从网络解析得到的数据    // 可以接受可变数组,因为可变数组继承于NSArray    NSArray * _appData;}- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    // 1.加载数据    _appData = [self loadAppData];        // 2.刷新UI    [self updateUI];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}// 一.第一步加载数据-(NSArray *)loadAppData{    // 1.(获取地址)获取url,得到plist文件的位置    NSURL *url = [[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil];        // 2.(通过地址下载)通过数组或者字典的url解析方法加载plist文件,    //  *使用nsarray或者NSDictionary的方法,因为集合类型只有这两种    NSArray *arr = [NSArray arrayWithContentsOfURL:url];          // 3.(定义容器用于保存解压得到的数据)解析plist文件中的内容    // 定义一个容器,用于接收解压得到的内容,用可变数组就可以,因为可接收oc对象类型的任何数据    NSMutableArray *arrM = [NSMutableArray array];        // 4.(解压下载得到的压缩包,既未拆封的集合)开始遍历解压,解析下载得到的NSArray中的NSDictionary内容    for (NSDictionary *dic in arr) {        // 5.定义一个解压工具(数据层的功能)        // 解析数据的方法不应该出现在view层,所以应该把解析数据的方法写在model层        // 既写到appData类的方法中        // 首先需要创建一个数据层的类对象,并且把解压得到的数据保存到类的属性中去        // 这里通过调用类方法,在类的方法内部实现了 1.类对象的创建  2.类对象属性的赋值        // 并且类方法的返回值是当前类的实例对象        // 这里定义解压工具的原因是,从网络下载得到的数据,要么是字典,要么是数组,不管是什么集合        // 一般都是提前规定好的,但是里面的key在之后的开发中可能会发生修改或者增加其他key        // 如果plist文件的内容发生改变,我们只需要修改数据的解压工具即可,降低耦合度,增加联动性        AppData *app = [AppData appWithDict:dic];                // 6.把解压得到的数据保存到我们事先准备好的容器中        // 如果我们不通过数据解压工具,那么这里保存的是一个字典        // 现在arrM中保存的是AppData类对象,而且这些类对象中都有和字典key相对应的属性,并且已经赋值        [arrM addObject:app];    }    // 7.返回从网络加载并且解析后得到的所有数据    return arrM;}// 二.刷新UI界面-(void)updateUI{    // 1.我们可以创建UIButton,UIView    // 这里创建的是我们自定义的视图,名字叫AppView    // 通过调用一个类方法来返回自定义视图,不能使用alloc init是因为需要一些操作来找到我们自定义的视图    // 然后才能初始化,我们把这一系列的操作都封装到了appView的这个类方法中    AppView *appView = [AppView createAppView];        // 2.这里需要一些计算,来根据生成的个数自动的设置我们生成的AppView应该在什么位置    // 定义行数,我们规定一行显示3个应用图标,所以这里设置为3    NSInteger colNum = 3;        // 3.获取自定义视图模板的宽和高    CGFloat appW = appView.bounds.size.width;    CGFloat appH = appView.bounds.size.height;        // 4.计算应用图标与手机屏幕的间距:屏幕的宽度-3个应用的宽度,再除以应用个数+1,因为3个应用会有4个间距    CGFloat margin = (self.view.bounds.size.width - (appW * colNum)) / (colNum + 1);        // 5.根据从网络获取到的数据_appData是一个数组,根据它的长度循环创建自定义视图    for (NSInteger i = 0 ; i < _appData.count; i++) {        // (1) 创建自定义的appView视图         AppView *appView = [AppView createAppView];                // (2) 计算当前的视图属于第几竖列        NSInteger col = i % colNum;                // (3)计算视图x的位置:左间距margin+(自定义视图的宽+间距margin)*当前第几列竖列        CGFloat appX = margin + (appW + margin) * col;                // (4)计算当前的视图属于第几横行        NSInteger row = i / colNum;                // (5)计算视图y的位置:上间距margin+(自定义视图的高+间距margin)*当前第几横行        CGFloat appY = margin + (appH + margin) * row;        // (6)x,y,宽和高,都已经计算好了,直接设置生成的视图位置        appView.frame = CGRectMake(appX, appY, appW, appH);                // (7)给属性appData赋值,使用了set方法,我们在set方法中做了设置        // _appData[i]是一个数组,我们在从网络拉取数据的时候,就使用的AppData类进行的解析        // 所以数组中保存的数据不是字典,是AppData类型的,所以这里可以使用_appData[i]进行赋值        // 赋值的同时通过set方法,修改自定义视图的应用图标和应用名称        appView.appData = _appData[i];                // (8)把生成的自定义视图添加到view主视图上        [self.view addSubview:appView];    }        }@end

模型层:

"AppData.h"

////  AppData.m////  Created by Long.//  Copyright © 2016年 LongChuang. All rights reserved.//#import "AppData.h"@implementation AppData+(instancetype)appWithDict:(NSDictionary *) dict{    // 1.创建appData对象,并且将从字典获取的数据赋值给对象的属性    // 这里使用self创建对象,谁调用谁创建,返回父类    // 根据多态的特性可知,我们这里定义的是父类AppData类型,但实际创建的是调用此类方法的类对象的类型    // 如:一个集成AppData的子类调用,那么创建的就是子类类型    AppData *app = [[self alloc] init];        // 这里用于给类对象的属性赋值,现在假设字典中只有这2个key,我们完全可以手动写入    // 如果字典中有几百个key,写起来就不那么方便了    // app.name = dict[@"name"];    // app.icon = dict[@"icon"];            // 所以,所以,所以,可以调用系统自带的方法    // 可以自动识别app对象中的属性与dict字典中key 并且自动赋值    // 注意:类对象中的属性名称一定要与字典中的key关键字相同    [app setValuesForKeysWithDictionary:dict];        // 这里返回类对象,因为类对象中保存了从字典中解析得到的数据,并且赋值给类对象的属性    // 返回一个属性已经赋值的类对象给view视图    return app;}@end

显示层:

"AppView.h"

////  AppView.m////  Created by Long.//  Copyright © 2016年 LongChuang. All rights reserved.//#import "AppView.h"#import "AppData.h"@interface AppView()// 自定义视图中的:应用图标@property (weak, nonatomic) IBOutlet UIImageView *iconName;// 自定义视图中的:应用名字@property (weak, nonatomic) IBOutlet UILabel *contextLabel;@end@implementation AppView// 返回当前自定义视图的类对象+(instancetype)createAppView{    // 这里相当于我们自定义了一个视图,也是UIView类型的,但是我们不想用系统的UIView类型    // 需要一个自定义的模板    // 第一步就是找到我们自定义的模板    // 第二步就是根据模板创建对象        // 1.(找到自定义模板)自定义的视图是xib格式,与代码中UINib是同一个东西,也叫nib    // 首先需要找到我们自定义的视图nib 这里的@"AppView"不是当前类的名字,是自定义xib的名字AppView.xib    // bundel设置为nil,就表示使用的是mainBundle    UINib *nib = [UINib nibWithNibName:@"AppView" bundle:nil];            // 2.(通过自定义模板创建对象)通过nib实例化对象    AppView *appView = [[nib instantiateWithOwner:nil  options:nil]firstObject];        // 3.返回自定义视图对象给方法调用者    return appView;}// 在控制层循环创建视图的时候,把从网络获取的数据复制给这个AppData-(void)setAppData:(AppData *)appData{    // 把网络数据中的应用图片名字和应用程序名字赋值给视图的属性    _appData = appData;    self.iconName.image = [UIImage imageNamed:appData.icon];    self.contextLabel.text = appData.name;}@end

你可能感兴趣的文章
前端面试
查看>>
React Hooks 异步操作踩坑记
查看>>
聊聊编码那些事,顺带实现base64
查看>>
TypeScript for React (Native) 进阶
查看>>
React 和 ReactNative 的渲染机制/ ReactNative 与原生之间的通信 / 如何自定义封装原生组件/RN中的多线程
查看>>
JavaScript实现DOM树的深度优先遍历和广度优先遍历
查看>>
webpack4 中的 React 全家桶配置指南,实战!
查看>>
react 设置代理(proxy) 实现跨域请求
查看>>
通过试题理解JavaScript
查看>>
webpack的面试题总结
查看>>
实践这一次,彻底搞懂浏览器缓存机制
查看>>
Koa2教程(常用中间件篇)
查看>>
React Hooks 完全指南
查看>>
React16常用api解析以及原理剖析
查看>>
教你发布你npm包
查看>>
nvm 和 nrm 的安装与使用
查看>>
React Hooks 一步到位
查看>>
React Redux常见问题总结
查看>>
前端 DSL 实践指南
查看>>
ReactNative: 自定义ReactNative API组件
查看>>