1.类扩展和分类的区别
- 类扩展:没有名字
- 可以为某个类增加额外的属性、成员变量和方法
- 分类:有名字
- 只能扩充方法,不能扩充成员变量,如果在分类中声明了一个属性,分类只会生成这个属性的getter/setter方法的声明。
2.UIView的frame和bounds区别
- frame:控件矩形框在父控件中的位置和尺寸——是以父控件的左上角为坐标原点
- bonus:控件矩形框的位置和尺寸——是以自己的左上角为坐标原点
3.Xcode引用资源的时候,每个选项的含义
- copy:
- 勾选copy,会把资源拷贝一份到项目的文件夹中(建议勾选,因为这样修改项目中的资源不会影响源资源)
- Added folder:
- 如果勾选Create groups ,只会会创建一个虚拟的文件夹,程序打包后,安装包中不存在这个文件夹
- 如果勾选Create folder references ,真的创建一个文件夹,程序打包后,安装包中真的有这个文件夹
- Add to targets :
- 要不要把资源打包到软件安装包中去,一定要勾选,不勾选到时候程序打包后,安装包中没有这个资源。
4.如何监听scrollView停止滚动
- 使用代理方法监听scrollView停止滚动
- 设置代理属性
- 遵守UIScrolLViewDelegate协议
- 实现代理方法
-
scrollViewDidEndDragging:已经停止拖拽的时候调用
- decelerate == NO 的时候,停止滚动
scrollViewDidEndDecelerating:减速完毕的时候调用
-
5.定时器一般有什么作用?以及如何使用定时器
- 作用:每隔一段时间去做一事件
- 开启定时器 [NSTimer scheduleTimerWithTimeInterval:target:selector:uerInfo:repeats:]返回的是一个自动执行任务的定时器
- 关闭定时器:invlidate
6.scrollView的使用场景
- app首页最新新闻页的分页浏览
- 音乐播放器下拉刷新
- 图片缩放
7.UIScrolLView无法滚动的原因
- uerInteractionEnabled = no
- scrollEnable = no
- 没有设置contentSize
- contentSize的尺寸小于等于scrollView的尺寸
8.scrollEnable和userInteractionEnable的区别
- scrollViewEnabled 是不能滚动,界面还可与用户进行交互
- userInteractionEnable如果设置为no,那么用户不能与外界进行交互了,即scrollView以及内部的所有子控件都不能和用户交互了
9.alwaysBounceVertical 和alwaysBounceHorizontal作用
- 默认是NO
- 如果设置为YES,可以应用于下拉刷新,并且不管有没有设置contentSize,总是有弹簧效果
10.如何监听UIScrollView的各种行为
- 通过代理监听scrollView的滚动
- scrollViewDidScroll:当scrollView正在滚动的时候调用,调用非常频繁
- scrollViewWillBeginDragging:用户即将开始拖拽的时候调用
- scrollViewDidEndDragging:已经停止拖拽的时候调用
- scrollViewDidEndDecelerating:减速完毕的时候调用
11.代理的注意点
- 任何对象都可以成为scrollView的代理
- 系统提供的代理属性是用weak修饰的,如果用strong会导致循环引用问题
12.利用UIScrollView如何实现内容缩放
- 创建scrolLView,在scrollView上面添加子控件
- 设置contentSize
- 设置代理属性
- 遵守代理UIScrollViewDelegate代理协议
- 实现代理方法
- viewForZoomingInScrollView:返回需要缩放的子控件
- 设置缩放比例
- maxmumScale
- minmuScale
13.如何监听控件的行为
- 用delegate属性的可以使用代理方法监听控件的行为
- 继承自UIConroll的可以使用addTarget:方法
14.用一个属性引用UI控件的时候为什么可以用weak?
- 因为UI控件添加到父控件中以后,会有强指针指向这个对象,就可以保证这个对象不会被销毁
- 再搞一个属性引用这个对象,用弱引用就可以
15.如何隐藏一个控件
- 设置hidden = YES
- 设置alpha = 0.0
16.如何用按钮来实现图片上、文字下的效果
- 自定义按钮实现
- -(CGRect)titleRectForContentRect:(CGRect)contentRect{
// 返回文字的frame
} - -(CGRect)imageRectForContentRect:(CGRect)contentRect{
// 返回图片的frame
}
- -(CGRect)titleRectForContentRect:(CGRect)contentRect{
- 自定义按钮,实现layoutSubViews方法调整按钮内部子控件的位置和尺寸
17.通过代码如何设置内边距
- contentEdgeInsets = UIEdgeInsetsMake()
- titleEdgeInsets = UIEdgeInsetsMake()
- imageEdgeInsets = UIEdgeInsetsMake()
18.如何处理图片拉伸问题
- 创建可拉伸的图片
- resizableImageWithCapInsets:UIEdgeInsetsMake(10,10,10,10) resizingMode:..
19.在xcode中如何配置拉伸图片
- 选中图片
- 右边(Slicing)
- Slices:Horizontal and Vertical
- 上下左右设置
20.KVC的作用
- Key Value Coding: 键值编码,可以修改属性的值,并且可以修改私有的成员变量,可以取值
21.通过autolayout如何实现UILabel内容包裹?
- 设置最大宽度约束为:< = 某一个固定的值
- 只给UILabel设置位置约束,系统会根据显示的文字,自动计算高度和宽度
- 动态修改Label显示的文字
22.Masonry使用
- 注意点:通过代码添加约束,一定要禁止掉translatesAutoresizingMaskIntoConstraints属性
- 框架内部已经禁止了autoresizingMask转为对应约束的属性
- mas_makeConstraints:
- make.top.equalTo(self.view.mas_top).multiplied(1.0).offset(20);
-make.left.equalTo(self.view.mas_left).multiplied(1.0).offset(20); - make.right.equalTo(self.view.mas_right).offset(-20);
-make.bottom.equalTo(self.view.mas_bottom).offset(20);
- make:谁调用这个方法,就指谁
- multiplied(1.0)可以不写,默认就是乘以一
- (self.view.mas_left)可以写为(self.view)
- equalTo(self.view.mas_top)可以不写,不告诉参照默认就是父控件
- 可以合并
- make.top.and.left.offset(20);
- make.right.and.bottom.offset(-20)
- and也可以省略
- make.top.left.offset(20);
- make.right.bottom.offset(-20)
- 一句话
- 完整make.edges.equalTo(self.view).insets(UIEdgeInsets(20,20,-20,-20,))
- 简单make.edges.insets(UIEdgeInsets(20,20,-20,-20))
- 补充
- mas_equalTo(传入基本数据类型进行包装,包装成对象)
- equalTo(只能传入对象,不能将数据类型包装成对象)
- 将框架PCH文件中的宏导入项目中,就不用写mas_前缀了
- 包含了宏之后,equalTo也可以对基本数据类型进行包装
- MAS_SHORTHAND
- MAS_SHORTHAND_GLOBALS
- 更新约束:updateContraints:
- 特点:如果之前有这个约束会直接更新,如果没有会添加新的约束
- 删除之前所有的约束,添加新的约束remakeConstraints:
23.什么是适配
- 适配:适应兼容各种不同的情况
- 分类:
- 屏幕适配
- 系统适配
- 设备的分辨率
24.点和像素的区别
- 在用户眼中
- 屏幕是由无数个像素组成的,像素越多,屏幕越清晰
- 在开发者眼中
- 屏幕是由无数个点组成的,点又是由像素组成的
- 像素越多,屏幕越清晰
25.什么是Autolayout?
- autolayout是一种自动布局技术,专门用来布局UI界面
- 能够轻松的解决屏幕适配的各种问题
- 解决任何控件之间的相对关系问题
26.简单描述一下Autolayout的两个核心概念:约束和参照?
- 约束:通过给控件添加约束,决定控件的位置和尺寸
- 参照:添加的约束是相对于谁来添加的,是父控件还是同一级的控件
27.Autolayout的警告和错误
- 警告
- 控件的frame不匹配所添加的约束
- 错误
- 缺乏必要的约束,约束条件不够,至少要有四个
- 两个约束之间造成冲突,重复设置更新约束
28.通过代码添加约束的原则
- 对于两个同层级控件之间的约束关系,添加到他们的父控件上
- 对于两个不同层级控件之间的约束关系,添加到他们最近的共同的父控件上
- 对于有层次关系的两个view之间的约束关系,添加到层次较高的父控件上
29.什么是VFL
- Visual Format Language :可视化格式语言
- 苹果公司为了简化Autolayout的编码而推出的抽象语言
30.通过约束如何实现动画
-
[UIView animateWithDuration:1.0 animations:^{
[添加了约束的父控件 layoutIfNeeded];强制刷新
}
];
31.xib加载原理
- 解析器,解析xib,检测最外侧的view是什么类型
- 创建一个这种类型的控件:initWithColer:
- 将frame、背景色等设置转为对应的代码
- initWithCoder:创建子控件
- 将xib中的设置转为对应的代码
- 将子控件加载到父控件上去
- xib中子控件是否有连线,相当于代码中给父控件的属性是否赋值
- 通过代码创建一个控件,是不会主动去加载xib的,即使类名和xib名字一样,也不会去加载
32.通过xib或者storyboard创建控件,初始化操作可以在initWithFrame:方法中做吗?
- 如果是通过storyboard或者xib创建控件,初始化的时候是不会调用initWithFrame,会调用initWithCoder
- 初始化完毕会调用awakeFromNib方法,建议在awakeFromNib中做初始化操作
33.通过alloc/init 或者alloc/initWithFrame创建控件会不会主动加载xib
- 通过alloc/init或者alloc/initWithFrame创建控件不会主动加载xib,即使xib的名称和控件的类名一样
34.UITableViewController的认识
- UITableViewController继承自UIViewController
- 控制器内部有tableView属性,tableView强引用UITableView对象
- 控制器的view就是tableView
- 默认遵守了代理协议和数据源协议
- 不需要设置数据源和代理,控制器内部的UITableView对象已经设置好数据源和代理就是当前控制器
35.性能优化的思路
- 首先了解苹果内部创建cell的方式,是每当一个cell进入视野范围内就会调用一次cellForRowAtIndexPath:这个方法,当cell要显示的时候去创建cell,导致重复创建和销毁cell,很耗费性能,造成UI卡顿
- 假设一个UI界面上显示4个cell
- 当用户向上滚动的时候,可以tableView可以去缓存池中看有没有可以利用的cell,如果没有,就创建一个新的cell,当第五个cell完全显示出来的时候,把第一个cell放入到缓存池当中,绑定标识,注意重用标识要一致,当滚动到第六个cell即将要显示的时候,tableView可以去缓存池中看有没有可以重复利用的cell,根据标识,会找到第一个cell
- 重复利用第一个cell,保留cell的属性,使得第六个cell的地址和第一个cell的地址相同
- 如此循环利用cell可以优化性能,防止cell重复创建销毁,耗费性能
36.UITableVeiw的性能优化的实现步骤
- 1.首先去缓存池中看有没有可以循环利用的cell
- dequeueReuseableCellWithIdentifier:这个方法会返回一个cell给我们
- 2.如果缓存池中没有可循环利用的cell,需要自己创建一个新的cell
- if (cell == nil){
cell = [[UITableViewCell alloc]initWithStyle:reuseIndentifier:];
}
- if (cell == nil){
37.registerClass:的作用
- 根据标识去缓存池中取,如果缓存池中没有,希望tableView内部帮我们创建
- [tableView registerClass:[UITableViewCell class]forCellReuseIdentifier:]
- 根据标识,注册cell的类型为UITableViewCell
38.通过注册的方式,如何实现cell的重用
- 根据标识去缓存池中取,如果缓存池中没有,希望tableView内部帮我们创建
- [tableView registerClass:[UITableViewCell class]forCellReuseIdentifier:]
- 根据标识,注册cell的类型为UITableViewCell
- dequeueReuseableCellWithIdentifier:会根据ID去缓存池中去取可循环利用的cell,如果没有可循环利用的cell,会判断有没有根据这个标识注册对应的cell类型,如果注册了会自动创建这种类型的cell,并且绑定ID这个标识返回给我们。
- if语句不用写了
39.如何监听tableView内部cell的点击事件?
- 设置代理属性 self.tableView.delegate = self;
- 遵守<UITableViewDelegate>
- 实现代理方法:
didSelectRowAtIndexPath:
- 当用户点击选中某一行cell的时候,就会自动调用这个方法
- indexPath.row
- didDeselectRowAtIndexPath:不常用,当用户取消选中某一行的时候,调用这个方法
40.性能优化的具体实现
- 不直接创建cell,去缓存池中看有没有可以直接利用的cell
- 如果缓存池中没有可循环利用的cell,需要自己创建一个新的cell
- 把可循环利用的cell绑定一个标识,根据标识找到可以循环利用的cell
41.UITableView如何展示数据
- 设置数据源属性
- 遵守<UITableViewDataSource>
- 实现数据源方法
- numberOfSectionsInTableView:返回一共有多少组
- numberOfRowsInSection:返回每一组有多少行
- cellForRowAtIndexPath:展示每一行显示的内容
42.UITableView的cell有哪几种样式?
- group样式
- plain样式
43.通过代码自定义cell能在initWithFrame:方法中添加子控件吗?
- 不可以,自定义cell不同于自定义控件,cell的创建时通过initWithStyle:reuseIdentifier:方法,而不是通过initWithFrame:方法。因此,添加子控件只能通过重写initWithStyle:方法,并且要调用父类的initWithStyle:reuseIdentifier:根据绑定的标识创建添加对应的子控件
44.通过代码自定义cell能在initWithStyle:reuseIdentifier:方法中计算子控件的位置和尺寸吗?
- frame方式不可以,通过代码创建的自定义cell,布局子控件的方法要写在layoutSubViews方法,initWithStyle:reuseIdentifier:方法初始化方法,只能用于添加子控件,或者是一次性的统一的设置
- masonry方式可以
45.通过代码自定义cell,frame和Autolayout的方式有什么区别吗?
- frame方式是通过CGRectMake()的方法设置控件的x,y,宽度以及高度,布局子控件的方法必须写在layoutSubViews方法中
- autolayout设置约束的方式,可以在initWithStyle:reuseIndentifier方法中计算子控件的位置和尺寸,但是要等到控件添加到父控件以后才可以添加约束
46.通过xib和storyboard自定义cell对比?
- 通过xib方式自定义cell,可以通过传统的方式定义重用标识,根据ID区缓存池中去取可循环利用的cell,如果没有cell就自己创建;也可以通过注册的方式在viewDidLoad中根据ID注册一个xib文件,然后根据ID去缓存池中去取,如果缓存池中没有可利用的cell,就找有没有xib文件,如果没有xib文件,就注册创建一个xib文件,同时必须要设置rowHeight.
- 通过stroyboard自定义cell,定义一个重用标识,绑定标识,然后根据ID去缓存池中去取dequeue,如果缓存池中没有,方法内部会判断有没有注册的cell。如果没有注册,会自动去storyboard中找有没有这种标识类型的cell,如果有系统会加载这种类型的cell。如果主动注册了cell,就会加载注册的cell,就不会去storyboard中去找,注册的优先级大于storyboard,storyboard中加载的cell,可以不写rowHeight的代码
47.通过storyboard的方式如何加载cell?
- 根据ID去缓存池中去取dequeue,如果缓存池中没有,方法内部会判断有没有注册的cell。如果没有注册,会自动去storyboard中找有没有这种标识类型的cell,如果有系统会加载这种类型的cell。如果主动注册了cell,就会加载注册的cell,就不会去storyboard中去找,注册的优先级大于storyboard
48.字典转模型第三方框架的了解
- Mantle
- 所有模型都必须继承自MTModel
- 给NSObject写了一个子类
- JSONModel
- 所有模型都必须继承JSONModel
- 对项目有污染性
- MJExtension
- 不需要强制继承任何其他类
- 导入框架
- 导入框架的主头文件
- 给NSObject写了一个分类
-
mj_objectArrayWithKeyValuesArray:
- 把传入的字典数组转成模型数组
- 用什么类去调用就转成什么类型的模型
- `mj_objectArrayWithFile:`
- 把plist路径传进去就可以了
- 一般看到file就是全路径
- `mj_objectArrayWithFilename:@".plist"`
- 直接传入plist文件名称就可以
-
复杂的字典转模型
- 不用为模型提供类方法
- 模型里面写属性就可以
-
第一种方法:
- mj_objectArrayWithFilename:
- 模型里面有数组属性,数组中装的是哪个类型框架不知道
- 告诉框架数组属性装的哪个类型
- 导入主头文件
- 实现类方法
mj_objectClassArray
return @{@"cars":[Car class]};
- return @{@"cars":@"Car"}不用导入Car模型的头文件
- 当删除框架,不用这个框架的时候,可以删掉框架的主头文件,代码不会报错
-
另一种方法:
- 在mj_objectArrayWithFilename:之前告诉框架
- mj_setupObjectClassInArray:^NSDictionary *{
return @{@"cars":[Car class]};
}
49.设计框架需要考虑的问题
- 侵入性
- 侵入性大就意味着很难离开这个框架
- 易用性
- 比如少量代码实现N多功能
- 扩展性
- 很容易给这个框架增加新功能
50.简述registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier和registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier这2个方法的区别?
- registerClass 这个方法是根据ID 注册对应的cell类型,系统创建cell的方式是通过alloc/initWithStyle...
- registerNib 这个方法是根据ID 注册一个xib文件,系统创建cell的方式是通过加载xib文件.
51.如何计算一段文字的宽度和高度?
- 第一种情况:如果label 只有一行,通过sizeWithAttributes:这个方法,告知这段文字的字体和字体大小就可以计算这段文件的尺寸.
- 第二种情况:如果label需要换行计算高度,通过boundingRectWithSize: options: attributes:attributes context: 这个方法,告知这段文字的字体和字体大小,并且在一个限制的尺寸内计算这段文字的尺寸.
52.什么是自定义cell?
- 继承自系统的cell写一个自己的cell,给系统的cell扩充一些额外的功能
53.reloadData这个方法的作用
- 全局刷新,刷新整个表格,所有cell的数据都会刷新。
54.如何做动画刷新
- 通过局部刷新的方法,设置动画刷新
- 添加insert
- 删除delete
- 更新reload
55.如何实现左滑删除功能
- 用代理的方法实现左滑功能
- 设置代理
- 遵守代理协议
- 实现代理方法
- 只要实现了commitEditingStyle:forRowAtIndexPath:方法,就拥有左滑删除功能。
56.如何实现左滑出现N个按钮
-
editActionsForRowAtIndexPath:
返回的是一个数组,数组里装的是UITableViewRowAction对象- 创建UITableViewAction对象:rowActionWithStyle:title:handler:^(UITableViewRowAction * action ,NSIndexPath *indexPath){
} - 实现了这个方法,系统的titleForDeleteConfirmationsButtonForRowAtIndexPath以及commitEditingStyle:forRowAtIndexPath:的方法就没有作用了
- return @[action,action1];
- 删除:destructive和默认的default样式是一样的
- 关注:Normal样式
- 创建UITableViewAction对象:rowActionWithStyle:title:handler:^(UITableViewRowAction * action ,NSIndexPath *indexPath){
ios9之前必须实现commitEditingStyle:forRowAtIndexPath:这个方法,才能实现左滑删除功能,ios9之后,实现
editActionsForRowAtIndexPath:
这个方法,也可有左滑删除功能。
57.编辑模式的理解
编辑模式进入前,要隐藏删除按钮,点击编辑模式,显示删除按钮
-
self.tableView.editing = NO;默认是NO
- 一旦进入编辑状态就会改为YES
58.如何实现在编辑模式中多选
- 可以设置tableView在编辑模式下可以多选
- allowsMultipleSelectionDuringEditing = YES
59.简单描述下你对MVC的认识
- M :Model ,用来保存数据的,将数据传给控制器
- V :View ,展示数据
- C :Control ,创建模型,把模型传给view来展示数据
60.iOS8以后,通过storyboard自定不等高的cell,对比通过storyboard自定义等高的cell有哪些区别?
- ios8以后storyboard定义不等高cell,对比等高cell,需要增加一个估算高度约束的设置和自动布局的设置
- 估算高度是为了让用户在数据较多的时候,有一个更好的用户体验,通过显示的滚动条来判断内容的多少
- 自动布局是通过设置的约束,以及约束的更新来自动布局,不用计算cell的高度,也不用返回cell的高度值
61.为什么在遍历一个数组的时候,不能一边一边删除,这样可能会导致什么问题?
- 开发中有一个原则,就是千万不能一边遍历一边删除,遍历的时候要保证数组的长度不变,因为每删除一个元素,其他元素在数组中的索引可能会发生变化
62.设置tableView的cell估算高度的作用
- 估算高度可以用来大概估算一个界面可以显示多少个cell,可以尽量写大一些,一般估算为200,大概就有五个cell会显示出来