1.@[]; 加入 nil 会闪退吗
会闪退,报错:
1 | -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[4] |
2.array[i] 会不会走 objectAtIndex
会走。
array[i] 如果数组越界,会崩溃报错:
1 | [__NSArrayI objectAtIndexedSubscript:]: index 6 beyond bounds [0 .. 4]' |
3.信号量 3 个网络接口返回执行 4
有些时候,我们需要阻塞发送请求的线程,比如在多个请求回调后统一操作的需求,而这些请求之间并没有顺序关系,且这些接口都会另开线程进行网络请求的。一般地,这种多线程完成后进行统一操作的需求都会使用队列组(dispatch_group_t)来完成,但是由于是异步请求,没等其异步回调之后,请求的线程就结束了,为此,就需要使用信号量来阻塞住发请求的线程。实现代码如下:
1 | dispatch_async(queue, 0), ^{ |
这样,请求的线程就可以等到回调结束后再结束了,再配合队列组就能完成上述的需求。这种技巧可用于以下场景:
- 多个请求结束后统一操作
- 多个请求顺序执行
4.hook delelgate 方法
参考链接:iOS hook delegate
5.交换方法传入参数 为什么需要先 addMethod
1 | + (void)exchangeInstanceMethodWithSelfClass:(Class)selfClass |
防止影响父类的方法。
init
方法并不是Person
类本身的实例(对象)方法,而是父类NSObject
的方法。由于Person
本身没有该方法,所以class_getInstanceMethod
获取到的方法是通过Person
的superclass
指针从NSObject
类中获取到了init
这个方法。method_exchangeImplementations
操作将NSObject
的init
方法的实现与Person
类的yxc_init
方法的实现进行互换了,这时候调用init
方法实际上是调用了yxc_init
方法。创建一个
Person
对象时,调用init
方法,运行时会去查找yxc_init
的实现,因为yxc_init
方法是Person
自身的方法,所以查找到了直接调用。(消息发送机制)而创建一个
NSObject
对象时,调用init
方法,运行时去查找yxc_init
方法的时候,NSObject
是没有这个方法,这个方法存在于Person
类中,所以查找完毕,还是找不到这个方法,就抛异常了。正确的 hook 做法是,先将 init 方法添加到 Person 类中,如果这个类当前有这个方法(而不是父类),则不添加,直接 exchange,否则添加了 init 方法,然后再将 yxc_init 方法的实现设置成 init 方法的实现。
参考链接:iOS Runtime 黑魔法方法交换(Method swizzling)
6.关联对象有几种策略,如何实现 weak
在关联对象释放的时候,调用objc_setAssociatedObject(object, key, nil, OBJC_ASSOCIATION_ASSIGN)
这样就把宿主对象的该 key 的关联对象清除了,外部读这个 key 的关联对象就是 nil
1 | extern void objc_setWeakAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value); |
参考链接:OC-AssociatedObject原理及weak关联对象的实现
7.响应者链 button 超出父视图一半能否响应点击事件
超出父视图的部分不能响应,在父视图内的部分可以响应。
如何扩大按钮的点击范围?
可以重写 button 的 pointInside: 方法
1 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { |
8.离屏渲染,为什么会触发
参考链接:知乎-关于iOS离屏渲染的深入研究
9.判断当前任务在哪个 queue 中
dispatch_queue_get_label
参考链接:判断代码在哪个队列中运行
10.SDWebImage 内存缓存怎么实现的
参考链接:iOS-SDWebImage缓存机制
11.json 转 model,Runtime 能否获取到自定义属性的类型
class_copyPropertyList
可以获取到属性列表
property_getName
可以获取到属性名
property_getAttributes
可以获取到成员类型
12.tableView 快速滑动 卡顿发生可能原因
1.提前计算并缓存好高度,因为 heightForRow 最频繁的调用。
- (UITableViewCell)tableView:(UITableView)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath;
2.异步绘制,遇到复杂界面,性能瓶颈时,可能是突破口。
3.滑动时按需加载,这个在大量图片展示,网络加载时,很管用。(SDWebImage 已经实现异步加载)。
4.重用 cells。
5.如果 cell 内显示得内容来自 web,使用异步加载,缓存结果请求。当 cell 中的部分 View 是非常独立的,并且不便于重用的,而且“体积”非常小,在内存可控的前提下,我们完全可以将这些 view 缓存起来。当然也是缓存在模型中。
6.少用或不用透明图层,使用不透明视图。对于不透明的 View,设置 opaque 为 YES,这样在绘制该 View 时,就不需要考虑被 View 覆盖的其他内容(尽量设置 Cell 的 view 为 opaque,避免 GPU 对 Cell 下面的内容也进行绘制)
7.减少 subViews。分析 Cell 结构,尽可能的将 相同内容的抽取到一种样式 Cell 中,前面已经提到了 Cell 的重用机制,这样就能保证 UITbaleView 要显示多少内容,真正创建出的 Cell 可能只比屏幕显示的 Cell 多一点。虽然 Cell 的’体积’可能会大点,但是因为 Cell 的数量不会很多,完全可以接受的
8.少用 addView 给 cell 动态添加 view,可以初始化的时候就添加,然后通过 hide 控制是否显示。
13.括号算法
LeetCode 题目链接:括号生成
14.CocoaPods 缓存存在哪里,pod install 执行
~/Library/Caches/Cocoapods