day06-07-UITableView

来源:互联网 发布:js混淆怎么读 编辑:程序博客网 时间:2024/05/22 17:20

一、什么是UITableView?
1. 再iOS开发中,要实现表格数据展示,做常用的做法就是使用UITableView
2、UITableView继承自UIScrollView,因此支持垂直滚动,而且性能极佳
3、UITableView的两种样式:UITableViewStylePlain、UITableViewStyleGrouped
4.UITableView 的常用属性

//分隔线 [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine]; /**  32位真彩位:ARGB(Alpha、red、green、blue)  24位真彩位:RGB  */ [self.tableView setSeparatorColor:[UIColor colorWithRed:1.0 green:1.0 blue:0 alpha:1.0]]; //setTableHeaderView视图通常用于放置图片轮播器内容,与分组无关 UIView *headerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 20, 20)]; [headerView setBackgroundColor:[UIColor redColor]]    ; [self.tableView setTableHeaderView:headerView]; //setTableFooterView视图通常做上拉刷新功能 UIView *footerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 20, 20)]; [footerView setBackgroundColor:[UIColor redColor]]; [self.tableView setTableFooterView:footerView];

二、如何展示数据
1、UITableView需要一个数据源来显示数据
2、UITableView会向数据源查询:一共有多少行数据、每一行显示什么数据
3、没有设置datasource的UITableView,只是一个空壳
4、凡是遵守UITableViewDatasource协议的oc对象,都可以是UITableView的datasource
5、tableView &datasource的关系
6、tableView展示数据的过程:

//1.调用数据源的下面方法得知一共有多少组数据- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;//2.调用数据源的下面方法得知每一组有多少行数据- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;//3.调用数据源的下面方法得知每一行显示什么内容- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

四、字典转模型举例(嵌套字典数组的模型转化)

////  HSCarGroup.m//  20160321-汽车品牌////  Created by devzkn on 3/21/16.//  Copyright © 2016 hisun. All rights reserved.//#import "HSCarGroup.h"@implementation HSCarGroup- (instancetype)initWithDictionary:(NSDictionary *)dict{    //KVC    self = [super init];//初始化父类属性    if (self) {        //初始化自身属性--将字典转化为HSCarGroup数据模型        [self setValue:dict[@"title"] forKey:@"title"];        //dict[@"cars"] 存放的是字段数组,与解析plist文件之后得到的数组类型一致;因此可以将dict[@"cars"]字典数组转化成HSCar模型数组        [self setCars:[HSCar cars:dict[@"cars"]]];    }    return self;}+ (instancetype)carGroupWithDictionary:(NSDictionary *)dict{    return [[self alloc]initWithDictionary:dict];}+ (NSArray *)carGroups{    NSMutableArray *tmpArrayM = [NSMutableArray array];    //解析plist    NSString *path = [[NSBundle mainBundle] pathForResource:@"cars_total" ofType:@"plist"];    NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];    for (NSDictionary *dict in  arrayDict) {        [tmpArrayM addObject:[self carGroupWithDictionary:dict]];    }    return tmpArrayM;}- (NSString *) description{    return [NSString stringWithFormat:@"<%@: %p> {title: %@, cars: %@}",self.class,self,self.title,self.cars];}@end

2. KVC 之数组取值(常常应用于tableVie的索引数组生成)

// *****右侧索引列表*********/** 返回的索引数组的“元素内容”和分组无关;索引数组的下表对应分组的下标 */- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView {    //1.使用遍历方式获取索引数组//    NSMutableArray<NSString *> *indexTitleArrayM = [NSMutableArray array];//    for (HSCarGroup *CarGroup in  self.carGroups) {//        [indexTitleArrayM addObject:CarGroup.title];//    }//    return indexTitleArrayM;    //2.KVC(键值编码) cocoa的大招,用于间接修改、获取对象的属性的一种方式(字典转模型、过滤数组获取数据)    /**     1>使用kvc在获取数据时,如果取值对象没有包含keypath的“键名”,会自动进入对象的内部查找     2》若取值的对象是一个数组,则取值结果也是一个数组     *///    NSLog(@"%@",[self.carGroups valueForKeyPath:@"cars.name"]);    return [self.carGroups valueForKeyPath:@"title"];}

五、MVC(model、view、controller)
1、MVC的几个明显特性(体现)
1》View上面显示什么内容,取决于model
2》只要model数据改了,View的显示状态会跟着变更
3》controller负责初始化model,并将model数据传递给view去解析展示

2、MVC特性的应用(tableView的行移动、添加、删除)

/** 支持手势拖拽删除。删除事件的处理需要自己处理-》MVC,只要修改model,view显示的状态内容也会跟着改变 1.编辑风格类型: typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) { UITableViewCellEditingStyleNone,0 UITableViewCellEditingStyleDelete,1 UITableViewCellEditingStyleInsert2 }; 2.表格格控件的修改操作实现过程,记得注重边界测试 */- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{    //1.处理删除键的监听事件    if ( UITableViewCellEditingStyleDelete == editingStyle) {        //1>删除处理,操作datasource        [self.dataList removeObjectAtIndex:indexPath.row];        //2>刷新表格        //*(重新加载所有数据)//        [self.tableView reloadData];        //*deleteRowsAtIndexPaths 表格控件动画地删除指定的行        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];    }else if (UITableViewCellEditingStyleInsert == editingStyle){        //2.插入数据处理        [self.dataList insertObject:@"new lydia" atIndex:indexPath.row+1];        NSIndexPath *idxPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];        //表格控件动画地在指定的indexPath数组添加指定的行        [self.tableView insertRowsAtIndexPaths:@[idxPath] withRowAnimation:UITableViewRowAnimationMiddle];    }}/** 移动表格的行 */- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{    //根据sourceIndexPath、destinationIndexPath调整model数据//    [self.dataList exchangeObjectAtIndex:sourceIndexPath.row withObjectAtIndex:destinationIndexPath.row];    //从数组取出源    id sourceObject = self.dataList[sourceIndexPath.row];    //从数组删除源    [self.dataList removeObjectAtIndex:sourceIndexPath.row];    NSLog(@"%@",self.dataList);    //将源插入数组的目标位置    [self.dataList insertObject:sourceObject atIndex:destinationIndexPath.row];    NSLog(@"%@",self.dataList);}#pragma mark - UITableViewDelegate代理方法/** If not implemented, all editable cells will have UITableViewCellEditingStyleDelete set for them when the table has editing property set to YES. */- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{    return (indexPath.row % 2)?UITableViewCellEditingStyleDelete :UITableViewCellEditingStyleInsert;}

表格的修改,常常用于本地数据缓存的场景,例如:个人通讯录、QQ聊天记录、本地日记本

六、cell的简介

UITableView的每一行都是一个UITableViewCell
1.cell的初始化: 通过datasource的tableView: cellForRowAtIndexPath: 方法来初始化每一行
2、UITableViewCell内部有一个默认的自视图ContentView :
ContentView是UITableViewCell所显示内容的父视图,可显示一些辅助视图(辅助视图的作用是显示一个表示动作的图标);contentView 默认有3个子视图(textLabel、detailTextLabel、UIImageView)
3、UITableViewCell的UITabelCellStyle属性:
用于决定使用contentView的哪些子视图,以及这个视图在contentView中的位置
4、cell的结构

这里写图片描述

七、cell的重用原理
1.重用原理
当滚动列表时,部分cell会移出窗口,UITableView会将窗口外的cell放入一个等待重用的对象池;
当UITableView要求datasource返回cell的时候,datasource会先查看这个对象池是否有未使用的cell,若有,datasource会用新的数据配置这个cell,并返回给UITableVIew重新显示到窗口中,从而避免创建新的对象。
2、解决一个TableView同时拥有不通类型的cell的问题
解决方案:
在初始化cell的时候,传入一个特定的“字符串标识”(通常使用cell的类名)来给cell的reuseIdentifier属性赋值;
当UITableView 要求datasource返回cell的时候,此时就利用reuseIdentifier属性到对象词中查找对应类型的cell对象,若找到就重用,否则利用这个reuseIdentifier属性来实例化一个cell对象
3. cell重用的例子:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    // 1.定义一个cell的标识      static NSString *ID = @"mjcell";    // 2.从缓存池中取出cell      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];    // 3.如果缓存池中没有cell      if (cell == nil) {        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];    }    // 4.设置cell的属性...    return cell;}

4、单元格循环引用概念

八、使用xib封装一个View的步骤
1、new一个xib文件来描述一个View的内部结构
2、new一个自定义的视图类(继承自xib根对象的class),类名通常与xib文件名保存一致
3、将xib中的控件与自定义视图类的.m文件建立连线 (建立连线之前,对根对象的class指定为刚刚新建的控件->在xi b属性面板指定可重用标识符
4、提供一个类方法,返回一个创建好的自定义视图类(屏蔽从xib加载的过程)
5、提供一个模型属性让外界传递模型数据,重写模型属性的setter方法(将模型数据展示到对应的子控件上面)

九、delegate:父控件(视图控制器)监听子控件的事件,当子控件发生某些事情的时候,通知父控件工作--备注:父控件通知子控件工作,直接调用子控件的方法即可

0、如果使用强引用,将造成循环的强引用--》儿子只能对父亲进行弱引用

@property (nonatomic,weak) id<HSGroupBuyingFooterViewDelegate> delegate;//在oc中,只有没有强用的时候,才会被立即释放;一旦自定义视图称为视图控制器的视图包含,极自定义视图为视图控制器的儿子时,且视图控制器为自定义视图(儿子)的代理,此时如果代理是强引用,将造成循环的强引用,”你中有我,我中有你“。--永远呆在内存

这里写图片描述

1、delegate的使用场合
1》对象A内部发生了一些事情,想通知对象B,对象A想传递数据给对象B
2》对象B想监听对象A内部发生了什么事情
3》对象A想在自己的方法内部调用对象B的某些方法,并且对象A不能对对象B有耦合依赖

2、使用delegate的步骤
1》搞清楚谁 是 谁的 delegate
2>定义代理协议(协议名称的命名规范:控件类名+Delegate)
3》定义代理方法:
*代理方法一般都定义为optional
*代理方法名称都以空间名开头;代理方法至少有个参数,用于将控件本事传递出去
4》设置代理对象(代理对象遵守协议,并实现协议方法)
5》在恰当的时刻调用delegate的协议方法,来通知delegate发生了什么事情(在调用之前判断代理是否实现了该代理方法)

十、通过代码自定义cell

1.new一个继承自UITableViewCell的类
2.重写initWithStyle: reuseIndentifier: 方法(对子控件的属性进行一次性赋值)
--有些属性只须设置一次,例如字体、固定的图片
3.并添加需要显示的子控件到contentView中
4、提供数据模型、frame模型
数据模型用于存放文字、图片数据;frame模型存放数据模型、所有子控件的frame、cell的高度
5.cell拥有一个frame模型
6、重写frame模型的setter方法(设置子控件的显示数frame);对frame的对象实例化采用懒加载方法,即进行getter方法的重写

////  HSStatusCell.h//  20160324-新浪微博////  Created by devzkn on 3/24/16.//  Copyright © 2016 hisun. All rights reserved.//#import <UIKit/UIKit.h>#import "HSStatus.h"@interface HSStatusCell : UITableViewCell//自定义视图的现实的数据来源于模型,即使用模型装配自定义视图的显示内容@property (nonatomic,strong) HSStatus *status;//视图对应的模型,是视图提供给外界的接口/** 通过数据模型设置视图内容,可以让视图控制器不需要了解视图的细节 */+ (instancetype) tableVieCellwWithStatus:(HSStatus *) status tableView:(UITableView *)tableView;//使用类方法获取自定义视图,参数用于视图的数据装配//+ (instancetype) tableVieCellwWittableView:(UITableView *)tableView;//使用类方法获取自定义视图@end
- (void)setStatus:(HSStatus *)status{    _status = status;    [self settingData];        //设置位置    [self settingFrame];}- (void) settingData{    //设置位置    [self.textView  setText:self.status.text];    [self.nameView setText:self.status.name];    [self.iconView setImage:self.status.iconImage];    if (self.status.picture.length > 0) {        [self.pictureView setImage:self.status.pictureImage];        [self.pictureView setHidden:NO];    }else{        [self.pictureView setImage:nil];//没有配图的时候,清空图片信息--cell重用的时候,对于可选视图要进行处理        [self.pictureView setHidden:YES];    }    if (self.status.vip) {        [self.vipView setImage:self.status.vipImage];        [self.vipView setHidden:NO];//显示VIP视图        [self.nameView setTextColor:[UIColor redColor]];    }else{        [self.vipView setImage:nil];//不是VIP的时候,清空VIP标识--cell重用的时候,针对可选视图进行特殊处理        [self.vipView setHidden:YES];        [self.nameView setTextColor:[UIColor blackColor]];    }}/** 设置位置信息 */- (void) settingFrame{    //定义间距    CGFloat padding =10;    CGFloat iconX = padding;    CGFloat iconY = padding;    CGFloat iconWidth = 30;    CGFloat iconHeiht = 30;    [self.iconView setFrame:CGRectMake(iconX, iconY, iconWidth, iconHeiht)];    //设置昵称,昵称的大小由文字的长度决定    /**     1.boundingRectWithSize 方法计算给定文本所占用的区域     2.options: 计算多行的的准确高度需要传入NSStringDrawingUsesLineFragmentOrigin     3、attributes 指定字体相关属性;UIKit框架中的第一个头文件   NSAttributedString.h     */    NSDictionary *nameDict = @{NSFontAttributeName:KnameFont};    CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];//返回一个x,y,都为0 的CGRect    nameFrame.origin.x = CGRectGetMaxX(self.iconView.frame)+padding;    nameFrame.origin.y = padding+(CGRectGetHeight(self.iconView.frame)-CGRectGetHeight(nameFrame))*0.5;    [self.nameView setFrame:nameFrame];    //设置VIP标识的frame    [self.vipView setFrame:CGRectMake(CGRectGetMaxX(self.nameView.frame)+padding, CGRectGetHeight(self.nameView.frame), 14, 14)];    //设置文本内容的frame    NSDictionary *textDict = @{NSFontAttributeName:KtextFont};    CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];    textFrame.origin.x = padding;    textFrame.origin.y = CGRectGetMaxY(self.iconView.frame)+padding ;    [self.textView setFrame:textFrame];    //设置picture的frame    [self.pictureView setFrame:CGRectMake(padding,CGRectGetMaxY(self.textView.frame)+padding, 100, 100)];}
#pragma mark - tableView delegate方法#if 1- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    /**     问题背景: 执行此方法的时候,cell还没被实例化;行高实在实例化cell之后,设置cell对象的模型属性status的时候计算的     解决方案:得到模型-》确定行高     */    //在cell实例化之前,获取行高-》先获取到模型    HSStatus *statuse = self.stautses[indexPath.row];    //开始计算行高//    CGFloat height = padding+iconView.frame.height+padding+textView.frame.height+pictureView.frame.height+padidng;    CGFloat iconViewHeight = 30;    CGFloat pictureViewHeight = 100;    CGFloat padding = 10;    CGFloat textViewHeight = [statuse.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} context:nil].size.height;    CGFloat height =iconViewHeight+textViewHeight+((statuse.picture.length >0 ? pictureViewHeight+padding: 0))+padding*2;    return height;}#endif

十一、cell类型&右侧视图及代理方法

//设置右侧视图    /**     1.UITableViewCellAccessoryDisclosureIndicator 箭头,可以提示用户们当前行是可以点击的,通常选择行会跳到新的页面     2、UITableViewCellAccessoryDetailButton 按钮,通常点击按钮可以做独立的操作,例如进行alertView;点击按钮并不会选中行     3、UITableViewCellAccessoryDetailDisclosureButton 箭头+按钮,它们是各自工作的控件     4、UITableViewCellAccessoryCheckmark  对号,通常提示用户该行数据设置完毕,使用的比较少     */    [cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];    //自定义右侧控件    /**     setAccessoryType 不满足实现的时候,才使用setAccessoryView进行自定义控件     1.setAccessoryView需要自行添加监听方法,应用场景通常是自定义cell,监听方法不要写在视图控制器中     2、     */    UISwitch *switcher = [[UISwitch alloc] init];    [switcher addTarget:self action:@selector(updateSwitcher) forControlEvents:UIControlEventValueChanged];    [cell setAccessoryView: switcher];#pragma mark - 代理方法通常没有返回值/** 点击右侧按钮的监听方法,此协议方法只为setAccessoryType服务,对于自定义控件setAccessoryView不会进行响应 */- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{    NSLog(@"%d,%s",indexPath.row,__func__);}//取消选择某一行,有箭头的,极少使用此协议方法,极容易出错- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{//    NSLog(@"%d,%s",indexPath.row,__func__);}//选中某一行,有箭头的- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{//    NSLog(@"%d,%s",indexPath.row,__func__);}

实现新浪微博的重点地方

1、. cellHeight 可以通过Status计算

/** 利用数据模型计算控件位置-》今儿计算cell的行高/- (void)setCellHeight{    CGFloat picHeight = (self.status.picture.length >0) ? KPading+CGRectGetHeight(self.pictureViewFrame): 0;    _cellHeight = CGRectGetHeight(self.iconViewFrame)+CGRectGetHeight(self.textViewFrame)+picHeight+2*KPading;}

2.Frame模型 替代数据模型(数据模型用于存放文字、图片数据;frame模型存放数据模型、所有子控件的frame、cell的高度)
1》目前存在什么问题?
所有的单元格控件的计算都是重复的,而且每次表格滚动,设置内容都会重新计算。
2》解决这个问题:
目前控制器中的数组保存的是status模型,将status模型替换为statusFrame模型{status,所有控件的位置},同样具有status模型
3》解决步骤
* 只是修改视图控制器中的代码,暂时不要动cell。 --(将原有的status模型替换为statusFrame模型)
**重写statusFrame set方法--设置子控件的显示数frame
* 重构代码一定要小步来

////  HSStatusFrame.m//  20160324-新浪微博////  Created by devzkn on 3/24/16.//  Copyright © 2016 hisun. All rights reserved.//#import "HSStatusFrame.h"#define KPading 10#define KnameFont [UIFont systemFontOfSize:14]#define KtextFont [UIFont systemFontOfSize:16]@interface HSStatusFrame ()//重写frame模型的setter方法(设置子控件的显示数frame);对frame的对象实例化采用懒加载方法,即进行getter方法的重写@end@implementation HSStatusFrame-(void)setStatus:(HSStatus *)status{    _status = status;    [self setIconViewFrame];    [self setNameViewFrame];    [self setVipViewFrame];    [self setTextViewFrame];    [self setPictureViewFrame];    [self setCellHeight];}/** 计算头像控件的frame*/- (CGRect)setIconViewFrame{    //定义间距    CGFloat iconX = KPading;    CGFloat iconY = KPading;    CGFloat iconWidth = 30;    CGFloat iconHeiht = 30;   _iconViewFrame= CGRectMake(iconX, iconY, iconWidth, iconHeiht);    return _iconViewFrame;}- (void)setNameViewFrame {    //设置昵称,昵称的大小由文字的长度决定    /**     1.boundingRectWithSize 方法计算给定文本所占用的区域     2.options: 计算多行的的准确高度需要传入NSStringDrawingUsesLineFragmentOrigin     3、attributes 指定字体相关属性;UIKit框架中的第一个头文件   NSAttributedString.h     */    NSDictionary *nameDict = @{NSFontAttributeName:KnameFont};    CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];//返回一个x,y,都为0 的CGRect    nameFrame.origin.x = CGRectGetMaxX(self.iconViewFrame)+KPading;    nameFrame.origin.y = KPading+(CGRectGetHeight(self.iconViewFrame)-CGRectGetHeight(nameFrame))*0.5;    _nameViewFrame =nameFrame;}- (void)setVipViewFrame{      _VipViewFrame = CGRectMake(CGRectGetMaxX(self.nameViewFrame)+KPading, CGRectGetHeight(self.nameViewFrame), 14, 14);}- (void)setTextViewFrame{    NSDictionary *textDict = @{NSFontAttributeName:KtextFont};    CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];    textFrame.origin.x = KPading;    textFrame.origin.y = CGRectGetMaxY(self.iconViewFrame)+KPading ;    _textViewFrame = textFrame;}/** 计算配图的frame*/- (void)setPictureViewFrame{    self.pictureViewFrame = CGRectMake(KPading,CGRectGetMaxY(self.textViewFrame)+KPading, 100, 100);}/** 计算cell的行高*/- (void)setCellHeight{    CGFloat picHeight = (self.status.picture.length >0) ? KPading+CGRectGetHeight(self.pictureViewFrame): 0;    _cellHeight = CGRectGetHeight(self.iconViewFrame)+CGRectGetHeight(self.textViewFrame)+picHeight+2*KPading;}//实例化frame模型- (instancetype)initWithStatus:(HSStatus *)status{    //KVC    self = [super init];//初始化父类属性    if (self) {        //初始化自身属性        [self setStatus:status];    }    return self;}//实例化frame模型+ (instancetype)statusFrameWithStatus:(HSStatus *)status{    return [[self alloc]initWithStatus:status];}//返回frame模型数组+ (NSArray *)statusFrames{    NSMutableArray *tmpArrayM = [NSMutableArray array];    //解析plist    NSArray *arrayDict = [HSStatus statuses];    for (HSStatus *status in  arrayDict) {        [tmpArrayM addObject:[self statusFrameWithStatus:status]];    }    return tmpArrayM;}@end

小结

1.编辑技巧:
1》代码块存放路径
/Users/devzkn/Library/Developer/Xcode/UserData/CodeSnippets 存储的是自定义的代码块文件
~/Library/Developer/Xcode/UserData/CodeSnippets--换新电脑,直接替换文件夹中的内容即可。
2》视图的分割线设置(使用UIView,高度为1,设置下背景颜色即可)

2、代理小结
1》作用:监听控件的某些事件、使用代理模式,是为了在程序直接”解耦”
2》代理例子:UITableView表格可以显示非常丰富的数据,为了达到这一效果,设置表格的”数据源”UITableViewDataSource
@required 必须实现的方法
@optional 可选的实现方法->不强求实现->如果实现了能得到特殊的效果,如果不实现,也不影响程序的正常运行
能够增加控件的灵活度
3》代理阶段性小结
1》》. 遵守协议,预先定义好方法,不实现,具体的实现工作由代理负责
<控件的名字+DataSource> 定义的与数据有关的方法,通常有返回参数
<控件的名字+Delegate> 定义的与事件有关的方法,通常用来监听控件事件的,通常没有返回值
2》》. 代理方法
* 方法名以控件名称开头(没有类前缀) -> 方便程序员编写的时候,快速找到需要的协议方法
* 第一个参数是自己 -> 意味着在协议方法中,可以直接访问对象的属性,或者调用方法
* 代理方法的返回值 -> 控制器向控件(委托)发送数据
3.

#pragma mark - 代理方法/** 一、表格工作观察的小结 1、numberOfRowsInSection要知道每组的总共有多少数据-》 2、heightForRowAtIndexPath计算每行行高 作用: 1》此方法的提前调用,是为了计算contentSize,因为UITableView继承自UIScrollView,UIScrollView 要指定了contentsize之后才能滚动 2》 确定屏幕应该显示多少行,也就确定了cellForRowAtIndexPath执行次数 -》 3、cellForRowAtIndexPath表格明细,懒加载--只有要显示的cell才会被实例化 二、UITableView行高设置的小结论---时刻关注性能问题 1、代理方法heightForRowAtIndexPath:优先级高于[_tableView setRowHeight:80];    应用场景:每一行的高度都不一样,例如新浪微博;但效率差 2、[_tableView setRowHeight:80]; 效率更高,适用于所有的cell高度一致的场景 */- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    NSLog(@"%s---------row-------%d",__func__,indexPath.row);    return (indexPath.row % 2) ? 60 : 44;//YES被定义为1//    return 44;可以使用[_tableView setRowHeight:80]替换,效率会更好}
  1. 错误分析

1.CUICatalog: Invalid asset name supplied: (null)

_pictureImage = [UIImage imageNamed:self.picture];//self.picture为nil,将会报错CUICatalog: Invalid asset name supplied: (null)