Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

day06-07-UITableView

$
0
0

一、什么是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)
作者:u011018979 发表于2017/6/27 19:06:34 原文链接
阅读:10 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>