更完善的解答
1. 什么是arc?(arc是为了解决什么问题诞生的?)
Auto Reference Counting,自动引用计数。
我猜是为了解决MRC下反复retain 和 release 很麻烦
能够降低程序崩溃和内存泄露的风险, 而且可以减少开发者的工作量, 能够大幅度提升程序的流畅性和可预测性
能加快运行速度速度。
2. 请解释以下keywords的区别: assign vs weak, __block vs __weak
assign 是给非OC对象类型用的,比如BOOL啊,Integer啊,CGFloat之类的。
对于OC对象相似的是unsafe_unretain.
weak 是会把被引用的对象设为nil的。unsafe_unretain不会。
assign用于简单的赋值, 不改变属性的引用计数, 用于 Objective-C 中的NSInteger,CGFloat以及 C 语言中int,float,double等数据类型.
weak用于对象类型, 由于weak同样不改变对象的引用计数且不持有对象实例, 当该对象废弃时, 该弱引用自动失效并且被赋值为nil, 所以它可以用于避免两个强引用产生的循环引用导致内存无法释放的问题.
strong会retain新值,release旧值。
如果要在接下来的block里要set某个对象,就需要用__block,block 中只具有"使用权"而不具有"修改权". 而__block说明符就为 block 提供了变量的修改权.
如果要在接下来的block里解决循环强引用,就需要用__weak
3. __block在arc和非arc下含义一样吗?
印象中不一样。非ARC是怎样的呢,(没写过ARC所以没印象)回头翻翻书。
4. 使用atomic一定是线程安全的吗?
不是,atomic只是在setter方法里加了@synchrosized而已。
如果A获取某个值,BCD正在修改这个值,atomic只能保证A能获取到一个值不至于autorelease,但是并不能保证获取到哪个。
如果要更好的线程安全可以用GCD来实现。同步队列和栅栏快。
5. 描述一个你遇到过的retain cycle例子。(别撒谎,你肯定遇到过)
class A{
var b = B()
func fooooooo(){
b.block = {() ->Void
self.... = ....
}
}
}
class B{
var block:(()->Void)?
}
例子二:NSTimer
例子三:delegate
6. +(void)load; +(void)initialize;有什么用处?
前者是在所有的类初始化时加载的,前者一般情况下用不着,会block住
后者在类自己执行一些初始化方法时加载,可以用来执行一些早期的快速简单的初始化,不应该用来做复杂的初始化。
当类对象被引入项目时, runtime 会向每一个类对象发送load消息.load方法还是非常的神奇的, 因为它会在每一个类甚至分类被引入时仅调用一次, 调用的顺序是父类优先于子类, 子类优先于分类. 而且load方法不会被类自动继承, 每一个类中的load方法都不需要像viewDidLoad方法一样调用父类的方法. 由于load方法会在类被import时调用一次, 而这时往往是改变类的行为的最佳时机. 我在DKNightVersion中使用method swizlling来修改原有的方法时, 就是在分类load中实现的.
initialize方法和load方法有一些不同, 它虽然也会在整个 runtime 过程中调用一次, 但是它是在该类的第一个方法执行之前调用, 也就是说initialize的调用是惰性的, 它的实现也与我们在平时使用的惰性初始化属性时基本相同. 我在实际的项目中并没有遇到过必须使用这个方法的情况, 在该方法中主要做静态变量的设置并用于确保在实例初始化前某些条件必须满足.
7. 为什么其他语言里叫函数调用, objective c里则是给对象发消息(或者谈下对runtime的理解)
OC是运行时语言, 不像某些在编译期就把需要执行的函数准备好,OC是在运行时才会让某个对象执行某个方法。 这样的优点是较为灵活。以及...
所有的消息都会在运行时才会确定,[obj message]在运行时会被转化为objc_msgSend(id self, SEL cmd, ...)来执行, 它会在运行时从选择子表中寻找对应的选择子并将选择子与实现进行绑定. 而如果没有找到对应的实现, 就会进入类似黑魔法的消息转发流程. 调用+ (BOOL)resolveInstanceMethod:(SEL)aSelector方法, 我们可以在这个方法中为类动态地生成方法.
我们几乎可以使用 runtime 改 Objective-C 中的一切:classpropertyobjectivarmethodprotocol, 而下面就是它的主要应用:
内省
为分类动态的添加属性
使用方法调剂修改原有的方法实现
...
8. 什么是method swizzling?
中文名叫方法调配。。就是把 某个 类的 两个方法 在运行时执行的内容调换过来。
可以用来修改或者debug一些系统自带方法。方法的调用时机就是在上面提到的load方法中, 不在initialize方法中改变方法实现的原因是initialize可能会被子类所继承并重新执行最终导致无限递归, 而load并不会被继承.
9. UIView和CALayer是啥关系?
UIView 有一个layer 属性是CALayer。CALayer主要用来显示图层。UIView 可以理解为用来显示图层的layer和用来响应手势操作的部分。
10. 如何高性能的给UIImageView加个圆角?(不准说layer.cornerRadius!)
用CGPath。 跟阴影同理,等我去找找具体实现的资料。
11. 使用drawRect有什么影响?(这个可深可浅,你至少得用过。。)
drawRect是UIView的绘制方法,可以进行一些绘制工作。
尽量少在这里做复杂的绘制。
UIView.setNeedsDisplay() 会调用这个方法重新绘制
12. ASIHttpRequest或者SDWebImage里面给UIImageView加载图片的逻辑是什么样的?(把UIImageView放到UITableViewCell里面问更赞)
会用URL作为key把图片缓存起来。先用这个key在缓存中查找,如果有则加载,如果没有则开始下载。下载完成后缓存图片并重载。
具体待我查查...
13. 麻烦你设计个简单的图片内存缓存器(移除策略是一定要说的)
写一个FIFO的存储机制,设置一定量的内存大小。每次添加新的图片后检查是否超出容量,如果超出则释放队列最前面的图片。
具体待我查查...
14. 讲讲你用Instrument优化动画性能的经历吧(别问我什么是Instrument)
Core Graphics 可以查看帧数... 像collectionview,tableview,mapview这样高速拖动的时候帧数50~60多是不错的...40多就略卡需要优化了...
优化的话,基础的的,reuse大家都知道,然后把opaque都设置为false(有个选项可以显示那些为true的UIView),然后把cornerRadius和shadow(主要是shadow)优化,不要用代码写。然后不要在delegate方法里使用类似 tableview.cellForIndexpath 还是 indexpathForCell 类似的方法 。
要求高一点,就尽可能缓存和预加载。而且不在delegate里减少需要计算的东西,和占内存的东西。VVebo有一个极致优化tableView的例子,是在后台进程先把layer的image绘制好,然后缓存起来要显示的时候再加载。
我做过一个mapView的优化,需要在地图上显示几千个marker,最后采用分层显示,和构建一个缓存库动态增加/减少的方法。
15. loadView是干嘛用的?
loadView是UIViewController的实例方法, 我们永远不要直接调用这个方法[self loadView]. 这在苹果的官方文档中已经明确的写出了.loadView会在获取视图控制器的view但是却得到nil时被调用.
loadView的具体实现会做下面两件事情中的一件:
如果你的视图控制器关联了一个 storyboard, 那么它就会加载 storyboard 中的视图.
如果试图控制器没有关联的 storyboard, 那么就会创建一个空的视图, 并分配给view属性
如果你需要覆写loadView方法:
你需要创建一个根视图.
创建并初始化view的子视图, 调用addSubview:方法将它们添加到父视图上.
如果你使用了自动布局, 提供足够的约束来保证视图的位置.
将根视图分配给view属性.
永远不要在这个方法中调用[super loadView].
16. viewWillLayoutSubView你总是知道的。。
viewwilllayoutsubviews(UIViewController) -> layoutsubviews(UIView) -> viewDidlayoutsubviews(UIViewController)
主要用来修改一些布局,位置
17. GCD里面有哪几种Queue?你自己建立过串行queue吗?背后的线程模型是什么样的?
main_queue global_queue 以及单个queue。
线程模型?不知道,去查查。
Serial Dispatch Queue
Concurrent Dispatch Queue
18. 用过coredata或者sqlite吗?读写是分线程的吗?遇到过死锁没?咋解决的?
CoreData和OC的sqlite不是线程安全的嘛。 coredata 建议为每个manageObjectContext一个线程。
改:在 Core Data 中使用并行的最重要的规则是:每一个NSManagedObjectContext必须只从创建它的进程中访问.
没遇到过死锁...也许不明crash就是死锁。待我今晚查查。
19. http的post和get啥区别?(区别挺多的,麻烦多说点)
1 get的参数都在url里嘛。post的在body里。
2 get的数据有限,post的较大。
3 根据 HTTP 协议的定义 GET 类型的请求是幂等的, 而 POST 请求是有副作用的, 也就是说 GET 用于获取一些资源, 而 POST 用于改变一些资源, 这可能会创建新的资源或更新已有的资源.
20. 我知道你大学毕业过后就没接触过算法数据结构了,但是请你一定告诉我什么是Binary search tree? search的时间复杂度是多少?我很想知道!
这题我不会,查资料得知:
左边的子节点都比父节点小(大),右边的子节点比左边的子节点大(小)。
搜索的时间复杂度是数的高度,插入和查找的时间复杂度均为lgN,但是在最坏的情况下仍然会有N的时间复杂度。