- ARC原理与深入了解
ARC就是代码中自动加入了retain/release
AutoReleasePool 原理
ARC什么时候也会引起内存泄露or crash?
循环引用
addObserver后记得在dealloc中调用removeObserver,否则会在通知消息时对象被销毁而引起crash
使用C语言的接口,其中的对象需要手动进行内存管理,操作不当会引起crash; - Runtime运行时机制原理与使用
理论上你可以在运行时通过类名/方法名调用到任何 OC 方法,替换任何类的实现以及新增任意类;// 具体实例可参见 JSpatch
函数执行:对象通过isa指针查找对应的class,先去查找cache中的SEL对应的方法,没查找再去方法列表中(字典方式)查找,未找到再去superclass中去查找,一直往上找,然后到根类后还未查找到,开始进行消息转发;
消息转发:resolveInstanceMethod -> forwardingTargetForSelector -> methodSignatureForSelector->
forwordInvocation -
doesNotRecognizeSelector;
运行时注册一个新类:
Class cls = objc_allocateClassPair(superCls, "JPObject", 0);
objc_registerClassPair(cls);
class_addMethod(cls, selector, implement, typedesc); - 动画机制
- 图层图像的原理与绘制
- 多线程原理
特别是NSOperationQueue与GCD的内部原理
GCD使用相关函数:
dispatch_async
dispatch_get_global_queue
dispatch_get_main_queue
dispatch_group_async
dispatch_group_notify
dispatch_barrier_async
dispatch_apply
Queue的背后原型是什么样的?系统线程池处理
NSOperationQueue有哪些使用方式?
NSOperation:继承使用,系统默认有NSBlockOperation跟NSInvocationOperation;main主要用于执行,start执行operation;
NSOperationQueue 以线程池的方式管理很多operation的执行;
NSOperationQueue 与 GCD 的区别:
NSOperationQueue是基于GCD的封装,GCD的速度更快;
NSOperationQueue可以很方便地调整执行顺序 设置最大并发数量,设置依赖关系;
NSOperationQueue支持KVO,可以监测operation是否正在执行(is Executed),是否结束(is finished),是否取消( is canceld);
- block的一些深入理解
block中的weak self,是任何时候都需要加的么?
不是的,只有在互相强引用引起循环引用的情况才使用weak self;
参考:https://stackoverflow.com/questions/20030873/always-pass-weak-reference-of-self-into-block-in-arc
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
MyObject *strongSelf = weakSelf;
[strongSelf doSomething];
}];
Retain cycles only matter if they exist in the static state of the object. While code is executing and its state is in flux, multiple and possibly redundant retains are fine.block就是一个里面存储了指向函数体中包含定义block时的代码块的函数指针,以及block外部上下文变量等信息的结构体。
Block结构体中含有isa指针,这就证明了Block其实就是对象,并具有一般对象的所有功能。这个isa指针被初始化为 NSConcreteStackBlock 或者 NSConcreteGlobalBlock 类的地址。
http://www.jianshu.com/p/51d04b7639f1PS:
UIView 的 animateWithDuration 与 dispatch_async 等其他GCD方法,由于是系统调用block,不用担心担心self引起的循环引用;
instrument的leaks可以调试循环引用;
- SDWebImage原理
- TableView卡顿
从缓存或本地读取图片给UIImage时候消耗的时间,需要把读取图像及设置图像的操作放到子线程中处理;
主要是 heightForRowAtIndexPath 跟 cellForRowAtIndexPath 调用比较频繁,要优化这里面的时间损耗及刷新显示;
界面流畅深入学习:
http://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/ - 响应链
UIApplication -> UIWindow -> UIViewController -> UIView -> sub view
hitTest + pointInside:
hitTest 方法底层会调用 pointInside;
hitTest底层实现:
{
if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01)
if(![self pointInside:point withEvent:event]) return nil;
self.subviews[i] -> [self convertPoint:point toView:childV] -> [childV hitTest:childP withEvent:event];//有子视图返回子视图,没有的话自己在响应区返回自己;
}
touches处理:? - NSTimer的深入了解
timer本身会对目标对象有强引用,runloop对timer有强引用;
timer不用了,一定要调动invalidate;
对象有timer的时候,timer的invalidate不要在dealloc中处理,因为timer强引用对象,如果timer不释放,self也不会释放,相当于循环引用;
调用performSelecter:afterDelay: 实际上是内部创建一个 Timer 并添加到当前线程的 RunLoop 中;所以如果当前线程没有 RunLoop,则这个方法会失效;(performSelector:onThread:创建Timer加入到对应的线程中); - method swizzling
- 如何高性能给UIImageView加圆角
corner radius 会发生离屏渲染,有性能问题
正确的做法是切换到工作线程利用CoreGraphic API生成一个offscreen UIImage,再切换到main thread赋值给UIImageView
使用CG绘制圆角
使用 CAShapeLayer - drawRect的用途
drawRect会利用CPU生成offscreen bitmap,从而减轻GPU的绘制压力,用这种方式最UI可以将动画流畅性优化到极致,但缺点是绘制api复杂,offscreen cache增加内存开销。UI动画流畅性的优化主要平衡CPU和GPU的工作压力;
https://medium.com/ios-os-x-development/perfect-smooth-scrolling-in-uitableviews-fd609d5275a5#.bct03ihv4 - loadView
在视图显示之前创建子视图什么的 - viewWillLayoutSubView 的使用
在布局需要刷新的时候调用, 被 [UIView(CALayoutDelegate) layoutSubLayersOfLayer:] 调用; - 数据库读写
sql的基本语法:
inner join、left join、right join的区别是什么?
使用coredata还是sqlite
读写分线程吗
遇到死锁?怎么解决死锁? - 网络问题
多个网络请求并发?
网络请求如何提高性能?
网络请求如何保证安全? - base64与md5区别
base64准确来说不是用来加密,只是将数据转换为只使用大写小写数字标点表示的字符串,易于显示处理,可解密;
md5将数据生成一个无法逆向解密的散列值; - 二叉搜索树
概念,时间复杂度
它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树;时间复杂度为O(log(n)); - KVC & KVO 深入理解
KVO:系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法;
KVC:运用了一个isa-swizzling技术,isa-swizzing就是类型混合指针机制。KVC通过isa-swizzing实现其内部查找定位。isa指针(is kind of 的意思)指向维护分发表的对象的类,该分发表实际上包含了指向实现类中的方法的指针和其他数据。下面的例子能准确说明:
[site setValue:@"sitename" forKey:@"name"];
//会被编译器处理成
SEL sel = sel_get_uid(setValue:forKey);
IMP method = objc_msg_loopup(site->isa,sel);
method(site,sel,@"sitename",@"name");
- 动画的深入理解
- 绘图的深入理解
- 保持界面流畅的技巧
http://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/
https://robots.thoughtbot.com/designing-for-ios-graphics-performance - 同步机制
@synchronized, NSLock, pthread mutexes, and OSSpinLock
http://perpendiculo.us/2009/09/synchronized-nslock-pthread-osspinlock-showdown-done-right/ - 内存缓存机制
http://mrpeak.cn/blog/ios-cache/
cache算法会影响整个app的表现
cache有哪些策略:FIFO,LRU,LRU-2,2Q等; - CPU & GPU 如何配合工作
- CoreAnimation
- CoreGraphic & OpenGLES
- 深入理解RunLoop
参考:http://blog.ibireme.com/2015/05/18/runloop/
RunLoop是不允许直接创建的,有 getcurrentloop 这样的函数获取;
线程与RunLoop是一一对应的,销毁是在线程结束时;
RunLoop 的核心就是一个 mach_msg() ,RunLoop 调用这个函数去接收消息,如果没有别人发送 port 消息过来,内核会将线程置于等待状态;
RunLoop 启动前内部必须要有至少一个 Timer/Observer/Source,所以 AFNetworking 源码创建的线程中,在 [runLoop run] 之前先创建了一个新的 NSMachPort 添加进去了;
一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。
- 网络
- 数据持久化
- performSelector:onThread
performSelector:onThread: 时,实际上其会创建一个 Timer 加到对应的线程去,同样的,如果对应线程没有 RunLoop 该方法也会失效。
问答
- 发送10个网络请求,然后再接收到所有回应之后执行后续操作,如何实现?
- 实现一个第三方控件,可以在任何时候出现在APP界面最上层?
- 实现一个最简单的点击拖拽功能?
如果在手放开时,需要根据速度往前滑动呢? - 如何提高一个应用程序的性能?
- 不同版本的APP,数据库结构变化了,如何处理?
PS:
知乎-如何面试iOS工程师
iOS中级面试题
一份有点难的iOS面试题
The End