UI基础

第一节

1.UI控件中拖线属性或方法常见错误

经典的错误
   1. 错误一
    描述:
      reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key testLabel.'
    原因: 有多余的连线
    解决: 删除多余的连线
 
   2.错误二
    描述:
      reason: '-[MainViewController clickBtn:]: unrecognized selector sent to instance 0x7feb69418640'
    原因:找不到对应的方法
    解决:1.添加对应的方法  2.删除多余的连线

2.UIView的常见属性

  • (void)addSubview:(UIView *)view;

    • 添加一个子控件view
  • (void)removeFromSuperview;

    • 将自己从父控件中移除
  • (UIView *)viewWithTag:(NSInteger)tag;

    • 根据一个tag标识找出对应的控件(一般都是子控件)
  • @property(nonatomic) CGRect frame;

    • 控件矩形框在父控件中的位置和尺寸(以父控件的左上角为坐标原点)
  • @property(nonatomic) CGRect bounds;

    • 控件矩形框的位置和尺寸(以自己左上角为坐标原点,所以bounds的x、y一般为0)
  • @property(nonatomic) CGPoint center;

    • 控件中点的位置(以父控件的左上角为坐标原点)

第二节

1.UIImageView的frame的设置

 // 设置frame的方式
    // 方式一
      UIImageView *imageView = [[UIImageView alloc] init];
      imageView.image = [UIImage imageNamed:@"1"];
     
//    imageView.frame = CGRectMake(100, 100, 267, 400);
//    imageView.frame = (CGRect){{100, 100},{267, 400}};
    */
    
    // 方式二
    /*
    UIImageView *imageView = [[UIImageView alloc] init];
    // 创建一个UIImage对象
    UIImage *image = [UIImage imageNamed:@"1"];
    // 设置frame
    imageView.frame = CGRectMake(100, 10, image.size.width, image.size.height);
    // 设置图片
    imageView.image = image;
     */
    
    // 方式三
    /*
    // 创建一个UIImage对象
    UIImage *image = [UIImage imageNamed:@"1"];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 10, image.size.width, image.size.height)];
    imageView.image = image;
     */
    
    // 方式四
    
    // 创建一个UIimageview对象
    // 注意: initWithImage 默认就有尺寸--->图片的尺寸
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
    
    // 改变位置
//    imageView.center = CGPointMake(200, 150);
    
    imageView.center = CGPointMake(self.view.frame.size.width * 0.5, self.view.frame.size.height * 0.5);

2.控件的创建方式

  • 一个控件有2种创建方式

    • 通过代码创建
    • 初始化时一定会调用initWithFrame:方法
  • 通过xib\storyboard创建

    • 初始化时不会调用initWithFrame:方法,只会调用initWithCoder:方法
    • 初始化完毕后会调用awakeFromNib方法

注意:
有时候希望在控件初始化时做一些初始化操作,比如添加子控件、设置基本属性
这时需要根据控件的创建方式,来选择在initWithFrame:、initWithCoder:、awakeFromNib的哪个方法中操作

3.xib的加载

方法1
NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"xib文件名" owner:nil options:nil]

方法2
UINib *nib = [UINib nibWithNibName:@"xib文件名" bundle:nil];
NSArray *views = [nib instantiateWithOwner:nil options:nil];

4.加载图片的方式

  1. imageNamed:与
  2. imageWithContentsOfFile:的区别
  • 加载Assets.xcassets这里面的图片:

  • 1> 打包后变成Assets.car
    
  • 2> 拿不到路径
    
  • 3> 只能通过imageNamed:来加载图片
    
  • 4> 不能通过imageWithContentsOfFile:来加载图片
    
  • 放到项目中的图片:

  • 1> 可以拿到路径
    
  • 2> 能通过imageNamed:来加载图片
    
  • 3> 也能通过imageWithContentsOfFile:来加载图片
    
图片的两种加载方式:
1> imageNamed:
  a. 就算指向它的指针被销毁,该资源也不会被从内存中干掉
  b. 放到Assets.xcassets的图片,默认就有缓存
  c. 使用场景:图片经常被使用

2> imageWithContentsOfFile:
  a. 指向它的指针被销毁,该资源会被从内存中干掉
  b. 放到项目中的图片就没有缓存
  c. 使用场景:不经常用,大批量的图片

5.Xcode插件大全

  • http://www.cocoachina.com/industry/20130918/7022.html

  • 必备

    • 文档注释生成:https://github.com/onevcat/VVDocumenter-Xcode
    • 自动检索图片名:https://github.com/ksuther/KSImageNamed-Xcode
    • 插件管理工具:https://github.com/mneorr/Alcatraz
  • 移除插件(可以使用上面提到的插件管理工具Alcatraz)

    • 到~/Library/Application Support/Developer/Shared/Xcode/Plug-ins文件夹中删除
  • 插件失效修复:http://joeshang.github.io/2015/04/10/fix-xcode-upgrade-plugin-invalid/

第三节

1.九宫格

  • 处在同一列的x值是一样的

  • 处在同一行的y值是一样的

  • 在九宫格中计算每一个小格子的位置

  • x值 = (小格子的宽 + 小格子之间的水平间距)*(格子的下标%格子的总列数)

  • y值 = (小格子的高 + 小格子之间的垂直间距)*(格子的下标/格子的总列数)

第四节

1.懒加载

1.作用:
1>用到的时候再加载
2>全局只会被加载一次
3>全局都可以使用

过程:
1.重写成员变量的get方法
2.在get方法中判断:
1>如果为空,加载数据
2>如果不为空,就直接返回数据

第五节

1.自定义控件与模型

  • 加载自定义控件分为两种:一种是代码加载自定义控件
* 首先在自定义控件的.m文件中重写initwithframe方法,在这个方法中创建控件

* 然后再laysubview方法中给控件设置尺寸

* 在.h文件中设置一个模型属性,然后在.m文件中充血模型属性的set方法,把传递进来的模型属性的值设置给对应控件

为自定义控件充血init 和 类工厂方法,

  • 宁外一种加载自定义控件的方法的事通过xib加载

    • 首先创建xib的文件,布局xib,关联xib对应的class

    • 在xib对应的class类的.h文件中,设置模型属性

    • 在.m文件中充血模型的set方法

    • 在.m属性中拉线给xib控件赋值

2.自定义按钮

注意: 在按钮外面改的尺寸,按钮的内部都会覆盖掉

    /*
    button.titleLabel.frame = CGRectMake(0, 0, 100, 70);
    button.imageView.frame = CGRectMake(100, 0, 70, 70);
     */

正确的做法

[button titleRectForContentRect:CGRectMake(0, 0, 100, 70)];
[button imageRectForContentRect:CGRectMake(100, 0, 70, 70)];


如果需要改变按钮控件内部的图片和label的frame的话又两种方法

一个是重写按钮内部的layoutsubview方法
另外一个是重写按钮内部的

  • (CGRect)titleRectForContentRect:(CGRect)contentRect

  • (CGRect)imageRectForContentRect:(CGRect)contentRect

3.图片的拉伸问题


  UIImage *resizableImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5 -1, imageWidth * 0.5 - 1)];
  

另外的一个方法

//    UIImage *resizableImage = [image stretchableImageWithLeftCapWidth:imageWidth * 0.5 topCapHeight:imageHeight * 0.5];

4.KVC

>1.利用KVC进行简单赋值

在简单赋值过程中会进行自动类型转换比如

[person setValue:@"19" forKeyPath:@"money"]; 
NSLog(@"%@-----%.2f", person.name, person.money)

打印结果整形转成浮点型

>2.KVC综合赋值

 forKey和forKeyPath
 1>forKeyPath 包含了所有 forKey 的功能
 2>forKeyPath 进行内部的点语法,层层访问内部的属性
 3>注意: key值一定要在属性中找到

>3.利用KVC修改类的私有成员变量

利用KVC修改类的私有成员变量

4.字典转模型

作用: 字典转模型
开发中是不建议使用setValuesForKeysWithDictionary:
1> 字典中的key必须在模型的属性中找到
2> 如果模型中带有模型,setValuesForKeysWithDictionary不好使
应用场景: 简单的字典转模型 ---> 框架 (MJExtention)

5.取值

6.把模型转成字典

   NSDictionary *dict = [person dictionaryWithValuesForKeys:@[@"name", @"money"]];

7.取出数组中所有模型的某个属性值

        XMGPerson *person1 = [[XMGPerson alloc] init];
        person1.name = @"zhangsan";
        person1.money = 12.99;
        
        XMGPerson *person2 = [[XMGPerson alloc] init];
        person2.name = @"zhangsi";
        person2.money = 22.99;
        
        XMGPerson *person3 = [[XMGPerson alloc] init];
        person3.name = @"wangwu";
        person3.money = 122.99;
        
        NSArray *allPersons = @[person1, person2, person3];
        NSArray *allPersonName = [allPersons valueForKeyPath:@"name"];
        
        NSLog(@"%@", allPersonName);

5KVO

KVO: Key Value Observing (键值监听)--->当某个对象的属性值发生改变的时候(用KVO监听)

    /*
     作用:给对象绑定一个监听器(观察者)
     - Observer 观察者
     - KeyPath 要监听的属性
     - options 选项(方法方法中拿到属性值)
     */
    [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    
    
    person.name = @"ls";
    
    person.name = @"ww";
    

    
    // 移除监听
    [person removeObserver:self forKeyPath:@"name"];

注意增加监听的时候记得移除监听,就好像添加通知要移除通知一样

增加监听以后可以在observeValueForKeyPath这个方法中监听到属性值的改变

第六节

1.监听scrollView各种行为的3大步骤(比如让控制 器监听scrollView的行为)

  • 设置scrollView的delegate(代理)为控制器对象
  • 控制器要遵守UIScrollViewDelegate协议
  • 控制器要实现UIScrollViewDelegate协议里面的代理方法
scrollView.delegate = 控制器;

  
@interface 控制器 ()  @end
 
 
#pragma mark -  代理 法
{
NSLog(@"scrollViewDidScroll-滚动"); }

2.代理使用的一般规律

  • 作用:用来监听控件的某些行为
  • 代理:是控制器对象
  • 代理:是id类型,并且是弱指针(weak)
  • 代理协议的格式:控件类名+Delegate,比如UIScrollViewDelegate、 UITableViewDelegate
  • 代理方法:方法名一般是控件名开头,比如UIScrollView的代理方法一般以scrollView开 头

3.如何监听控件的行为

  • 通过addTarget:

    • 只有继承自UIControl的控件,才有这个功能 UIControlEventTouchUpInside : 点击事件(UIButton)

    • UIControlEventValueChanged : 值改变事件(UISwitch、UISegmentControl、 UISlider)
      UIControlEventEditingChanged : 文字改变事件(UITextField)

  • 通过delegate 只有拥有delegate属性的控件,才有这个功能

4.NSTimer的使用

  • 开启定时器
 @property (nonatomic, weak) NSTimer *timer;
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
 // 返回 个 动开始执 任务的定时器
 
 self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self
 
// NSDefaultRunLoopMode(默认): 同一时间只能执行一个任务
// NSRunLoopCommonModes(公用): 可以分配一定的时间执行其他任务
// 作用:修改timer在runLoop中的模式为NSRunLoopCommonModes
// 目的:不管主线程在做什么操作,都会分配一定的时间处理定时器
  • 关闭定时器
  [self.timer invalidate];

5.UIScrollView

1.基本使用

  • 介绍
  • 设置内容尺寸(contentSize)
  • 不能滚动的原因

2.常见属性

  • 是否有弹簧效果
  • 是否总是有弹簧效果
    • 作用:下拉刷新,上拉加载
  • 是否显示滚动条
    • 滚动条的样式
  • 滚动条是imageView
  • 注意点:不要通过索引去subViews这个数组中去访问scrollView的子控件

3.偏移量和内边距

4.监听scrollView的各种行为

  • 代理的介绍
    • 代码创建scrollView和storyboard创建的区别
    • 代码创建要等到真正要显示的时候才会有滚动条

如何监听scrollView已经停止滚动 有2种情况
第一种手松开,scrollView就停止滚动 第二种,用户停止拖拽,但scrollView由于惯性继续滚动,并且减速

5.内容缩放

  • 通过代理告知哪一个控件需要缩放
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
  • 设置缩放的比例
* 设置minimumZoomScale 
* 设置maximumZoomScale   
  • 监听缩放的过程

跟缩放相关的其他代理方法
即将开始缩放的时候调用

  • (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view

正在缩放的时候调用

  • (void)scrollViewDidZoom:(UIScrollView *)scrollView
  • 禁止缩放的弹簧效果

第七节

1.Autolayout

  • Autolayout的2个核心概念

    • 约束:通过给控件添加约束,来决定控件的位置和尺寸
    • 参照:在添加约束时,是依照谁来添加(可以是父控件或者兄弟控件)
  • 代码实现Autolayout的注意点

  • 要先禁止autoresizing功能,设置view的下面属性为NO

  • view.translatesAutoresizingMaskIntoConstraints = NO;

  • 添加约束之前,一定要保证相关控件都已经在各自的父控件上

  • 不用再给view设置frame

  • 一个NSLayoutConstraint对象就代表一个约束

  • 创建约束对象的常用方法

+(id)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
view1 :要约束的控件
attr1 :约束的类型(做怎样的约束)
relation :与参照控件之间的关系
view2 :参照的控件
attr2 :约束的类型(做怎样的约束)
multiplier :乘数
c :常量

[图片上传失败...(image-cbf8ee-1520169654402)]

在添加时要注意目标view需要遵循以下规则:

  • 1)对于两个同层级view之间的约束关系,添加到它们的父view上

[图片上传失败...(image-42483c-1520169654402)]

  • 2)对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上

[图片上传失败...(image-dea5d5-1520169654402)]

  • 3)对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上

[图片上传失败...(image-f2d463-1520169654402)]

  • 在修改了约束之后,只要执行下面代码,就能做动画效果
[UIView animateWithDuration:1.0 animations:^{
    [添加了约束的view的父控件 layoutIfNeeded];
}];
  • 补充:
    • autolayout中baselines的选项可以为label和button设置下方对齐

2.VFL语言实现autolayout

使用VFL来创建约束数组
+ (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
format :VFL语句
opts :约束类型
metrics :VFL语句中用到的具体数值
views :VFL语句中用到的控件

创建一个字典(内部包含VFL语句中用到的控件)的快捷宏定义
NSDictionaryOfVariableBindings(...)

3.Masonry目前最流行的autolayout的第三方kuangjia

  • 框架地址

    • https://github.com/SnapKit/Masonry
  • Masonry两种简写的用法

默认情况下
mas_equalTo有自动包装功能,比如自动将20包装为@20
equalTo没有自动包装功能

如果添加了下面的宏,那么mas_equalTo和equalTo就没有区别
#define MAS_SHORTHAND_GLOBALS
// 注意:这个宏一定要添加到#import "Masonry.h"前面

默认情况下
width是make对象的一个属性,用来添加宽度约束用的,表示对宽度进行约束
mas_width是一个属性值,用来当做equalTo的参数,表示某个控件的宽度属性

如果添加了下面的宏,mas_width也可以写成width
#define MAS_SHORTHAND

mas_height、mas_centerX以此类推

第八节

1.���UITableView

  • 在tableview中,如果显示的内容没有撑满整个屏幕,可以通过在尾部设置tableview。viewforfoot的属性为一个空的view来达到撑满整个屏幕的效果,也可以改变tableview的样式为group

  • 在tableview中的cellforrowatindexpath空,���中谨记有if就要有else,因为table的cell都是循环引用的

  • UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行

  • UITableViewCell内部有个默认的子视图:contentView,contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图

注意:在开发中等号左右两边的类型要是同一类型

2.UITableViewCell

UITableViewCell重用


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

注意:tableview和tableviewcell有一个共同的特点就是他们一创建出来就已经确定了样式,在接下去的代码中用访问属性的点语法也改不了他们的样式

第九节

1.在UITableview中自定义等高cell

  • 第一种使用纯代码实现(frame)

新建一个继承自UITableViewCell的子类,比如XMGTgCell

@interface XMGTgCell : UITableViewCell
@end

在XMGTgCell.m文件中

  • 重写-initWithStyle:reuseIdentifier:方法
    • 在这个方法中添加所有需要显示的子控件
    • 给子控件做一些初始化设置(设置字体、文字颜色等)
/**
 *  在这个方法中添加所有的子控件
 */
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        // ......
    }
    return self;
}
  • 重写-layoutSubviews方法
    • 一定要调用[super layoutSubviews]
    • 在这个方法中计算和设置所有子控件的frame
/**
 *  在这个方法中计算所有子控件的frame
 */
- (void)layoutSubviews
{
    [super layoutSubviews];

    // ......
}

在XMGTgCell.h文件中提供一个模型属性,比如XMGTg模型

@class XMGTg;

@interface XMGTgCell : UITableViewCell
/** 团购模型数据 */
@property (nonatomic, strong) XMGTg *tg;
@end

在XMGTgCell.m中重写模型属性的set方法

  • 在set方法中给子控件设置模型数据
- (void)setTg:(XMGTg *)tg
{
    _tg = tg;

    // .......
}

在控制器中

  • 注册cell的类型
[self.tableView registerClass:[XMGTgCell class] forCellReuseIdentifier:ID];
  • 给cell传递模型数据
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 访问缓存池
    XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 设置数据(传递模型数据)
    cell.tg = self.tgs[indexPath.row];

    return cell;
}

2.在UITableview中自定义不登高的cell

给模型增加frame数据

  • 所有子控件的frame
  • cell的高度(cellHeight)
@interface XMGStatus : NSObject
/**** 文字\图片数据 ****/
// .....

/**** frame数据 ****/
/** 头像的frame */
@property (nonatomic, assign) CGRect iconFrame;
// .....
/** cell的高度 */
@property (nonatomic, assign) CGFloat cellHeight;
@end
  • 重写模型cellHeight属性的get方法
- (CGFloat)cellHeight
{
    if (_cellHeight == 0) {
        // ... 计算所有子控件的frame、cell的高度
    }
    return _cellHeight;
}

在控制器中

  • 实现一个返回cell高度的代理方法
    • 在这个方法中返回indexPath位置对应cell的高度
/**
 *  返回每一行cell的具体高度
 */
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    XMGStatus *status = self.statuses[indexPath.row];
    return status.cellHeight;
}
  • 给cell传递模型数据
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 访问缓存池
    XMGStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 设置数据(传递模型数据)
    cell.status = self.statuses[indexPath.row];

    return cell;
}

新建一个继承自UITableViewCell的子类,比如XMGStatusCell

@interface XMGStatusCell : UITableViewCell
@end

在XMGStatusCell.m文件中

  • 重写-initWithStyle:reuseIdentifier:方法
    • 在这个方法中添加所有可能需要显示的子控件
    • 给子控件做一些初始化设置(设置字体、文字颜色等)
/**
 *  在这个方法中添加所有可能需要显示的子控件
 */
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        // ......
    }
    return self;
}

在XMGStatusCell.h文件中提供一个模型属性,比如XMGStatus模型

@class XMGStatus;

@interface XMGStatusCell : UITableViewCell
/** 微博模型数据 */
@property (nonatomic, strong) XMGStatus *status;
@end

在XMGStatusCell.m中重写模型属性的set方法

  • 在set方法中给子控件设置模型数据
- (void)setStatus:(XMGStatus *)status
{
    _status = status;

    // .......
}

重写-layoutSubviews方法

  • 一定要调用[super layoutSubviews]
  • 在这个方法中设置所有子控件的frame
/**
 *  在这个方法中设置所有子控件的frame
 */
- (void)layoutSubviews
{
    [super layoutSubviews];

    // ......
}




3自定义不等高的cell 使用storyboard

对比自定义等高cell,需要几个额外的步骤(iOS8开始才支持)

  • 添加子控件和contentView之间的间距约束
  • 设置tableViewCell的真实行高和估算行高
// 告诉tableView所有cell的真实高度是自动计算(根据设置的约束来计算)
self.tableView.rowHeight = UITableViewAutomaticDimension;
// 告诉tableView所有cell的估算高度
self.tableView.estimatedRowHeight = 44;

如果要支持iOS8之前

  • 如果cell内部有自动换行的label,需要设置preferredMaxLayoutWidth属性
- (void)awakeFromNib
{
    // 手动设置文字的最大宽度(目的是:让label知道自己文字的最大宽度,进而能够计算出自己的frame)
    self.text_label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
}
  • 设置tableView的cell估算高度
// 告诉tableView所有cell的估算高度(设置了估算高度,就可以减少tableView:heightForRowAtIndexPath:方法的调用次数)
self.tableView.estimatedRowHeight = 200;
  • 在代理方法中计算cell的高度
XMGStatusCell *cell;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 创建一个临时的cell(cell的作用:根据模型数据布局所有的子控件,进而计算出cell的高度)
    if (!cell) {
        cell = [tableView dequeueReusableCellWithIdentifier:ID];
    }

    // 设置模型数据
    cell.status = self.statuses[indexPath.row];

    return cell.height;
}

- (CGFloat)height
{
    // 强制布局cell内部的所有子控件(label根据文字多少计算出自己最真实的尺寸)
    [self layoutIfNeeded];

    // 计算cell的高度
    if (self.status.picture) {
        return CGRectGetMaxY(self.pictureImageView.frame) + 10;
    } else {
        return CGRectGetMaxY(self.text_label.frame) + 10;
    }
}

第十节

1.iOS面试相关

  • https://github.com/lintaoSuper/trip-to-iOS

  • https://github.com/ipader/SwiftGuide

  • https://github.com/ChenYilong/iOSInterviewQuestions

  • stackoverflow(全英文, IT问答网站) 学习新东西

2. 数据刷新

  • 添加数据
  • 删除数据
  • 更改数据

3.全局刷新方法(最常用)

[self.tableView reloadData];
// 屏幕上的所有可视的cell都会刷新一遍

4.局部刷新方法

  • 添加数据
NSArray *indexPaths = @[
                        [NSIndexPath indexPathForRow:0 inSection:0],
                        [NSIndexPath indexPathForRow:1 inSection:0]
                        ];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];
  • 删除数据
NSArray *indexPaths = @[
                        [NSIndexPath indexPathForRow:0 inSection:0],
                        [NSIndexPath indexPathForRow:1 inSection:0]
                        ];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];
  • 更新数据(没有添加和删除数据,仅仅是修改已经存在的数据)
NSArray *indexPaths = @[
                        [NSIndexPath indexPathForRow:0 inSection:0],
                        [NSIndexPath indexPathForRow:1 inSection:0]
                        ];
[self.tableView relaodRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];

5.左滑出现删除按钮

  • 需要实现tableView的代理方法
/**
 *  只要实现了这个方法,左滑出现Delete按钮的功能就有了
 *  点击了“左滑出现的Delete按钮”会调用这个方法
 */
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 删除模型
    [self.wineArray removeObjectAtIndex:indexPath.row];

    // 刷新
    [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}

/**
 *  修改Delete按钮文字为“删除”
 */
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return @"删除";
}

6.左滑出现N个按钮

  • 需要实现tableView的代理方法
/**
 *  只要实现了这个方法,左滑出现按钮的功能就有了
 (一旦左滑出现了N个按钮,tableView就进入了编辑模式, tableView.editing = YES)
 */
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{

}

/**
 *  左滑cell时出现什么按钮
 */
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewRowAction *action0 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"关注" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
        NSLog(@"点击了关注");

        // 收回左滑出现的按钮(退出编辑模式)
        tableView.editing = NO;
    }];

    UITableViewRowAction *action1 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
        [self.wineArray removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }];

    return @[action1, action0];
}

7.进入编辑模式

// self.tabelView.editing = YES;
[self.tableView setEditing:YES animated:YES];
// 默认情况下,进入编辑模式时,左边会出现一排红色的“减号”按钮

8.在编辑模式中多选

// 编辑模式的时候可以多选
self.tableView.allowsMultipleSelectionDuringEditing = YES;
// 进入编辑模式
[self.tableView setEditing:YES animated:YES];

// 获得选中的所有行
self.tableView.indexPathsForSelectedRows;

第十一节

代理的使用步骤

  • 定义一份代理协议

    • 协议名字的格式一般是:类名 + Delegate
      • 比如UITableViewDelegate
    • 设计代理的细节
      • 一般都是@optional(让代理可以有选择性去实现一些代理方法)
      • 方法名一般都以类名开头
        • 比如- (void)scrollViewDidScroll:
      • 一般都需要将对象本身传出去
        • 比如tableView的代理方法都会把tableView本身传出去
    • 必须要遵守NSObject协议(基协议)
      • 比如@protocol XMGWineCellDelegate
  • 声明一个代理属性

    • 代理的类型格式:id<协议> delegate
@property (nonatomic, weak) id delegate;
  • 设置代理对象

  • 代理对象遵守协议,实现协议里面相应的方法

  • 当控件内部发生了一些事情,就可以调用代理的代理方法通知代理

    • 如果代理方法是@optional,那么需要判断方法是否有实现,直接调用可能会报错
if ([self.delegate respondsToSelector:@selector(wineCellDidClickPlusButton:)]) {
    [self.delegate wineCellDidClickPlusButton:self];
}

iOS监听某些事件的方法

  • 通知(NSNotificationCenter\NSNotification)

    • 任何对象之间都可以传递消息
    • 使用范围
      • 1个对象可以发通知给多个对象
      • 1个对象可以接受多个对象发出的通知
    • 要求:必须得保证通知的名字在发出和监听时是一致的
  • KVO

    • 仅仅是能监听对象属性的改变(灵活度不如通知和代理)
  • 代理

    • 使用范围
      • 1个对象只能设置一个代理(假设这个对象只有1个代理属性)
      • 1个对象能成为多个对象的代理
  • 如何选择?

    • 代理通知规范
    • 建议使用代理多于通知,能使用代理尽量使用代理

你可能感兴趣的:(UI基础)