iOS常见面试题(持续更新中)
1、UIView和CALayer的区别和联系?
- UIView 继承 UIResponder,而 UIResponder 是响应者对象,可以对iOS 中的事件响应及传递,CALayer 没有继承自 UIResponder,所以 CALayer 不具备响应处理事件的能力。CALayer 是 QuartzCore 中的类,是一个比较底层的用来绘制内容的类,用来绘制UI
- UIView 对 CALayer 封装属性,对 UIView 设置 frame、center、bounds 等位置信息时,其实都是UIView 对 CALayer 进一层封装,使得我们可以很方便地设置控件的位置;例如圆角、阴影等属性, UIView 就没有进一步封装,所以我们还是需要去设置 Layer 的属性来实现功能。
- UIView 是 CALayer 的代理,UIView 持有一个 CALayer 的属性,并且是该属性的代理,用来提供一些 CALayer 行的数据,例如动画和绘制。
2、UIResponder的理解
UIResponder类是专门用来响应用户的操作处理各种事件的,包括触摸事件(Touch Events)、运动事件(Motion Events)、远程控制事件(Remote Control Events)。我们知道UIApplication、UIView、UIViewController这几个类是直接继承自UIResponder,所以这些类都可以响应事件。当然我们自定义的继承自UIView的View以及自定义的继承自UIViewController的控制器都可以响应事件。
3、使用 drawRect有什么影响?
drawRect 方法依赖 Core Graphics 框架来进行自定义的绘制
缺点:它处理 touch 事件时每次按钮被点击后,都会用 setNeddsDisplay 进行强制重绘;而且不止一次,每次单点事件触发两次执行。这样的话从性能的角度来说,对 CPU 和内存来说都是欠佳的。特别是如果在我们的界面上有多个这样的UIButton 实例,那就会很糟糕了。这个方法的调用机制也是非常特别. 当你调用 setNeedsDisplay 方法时, UIKit 将会把当前图层标记为 dirty,但还是会显示原来的内容,直到下一次的视图渲染周期,才会将标记为 dirty 的图层重新建立 Core Graphics 上下文,然后将内存中的数据恢复出来, 再使用 CGContextRef 进行绘制
4、Bounds和Frame的区别?
- Frame改变的是自身大小,以父视图的坐标系为参照,从而确定当前视图在父视图中的位置
- Frame的大小改变时,当前视图的左上角位置不会发生改变,只是大小发生改变
- Bounds改变位置时,改变的是子视图的位置,自身没有影响;其实就是改变了本身的坐标系原点,默认本身坐标系的原点是左上角(0,0)。比如origins改为(0,100),那么左上角坐标变成了(0,100), 子视图的坐标就要相对于(0,100)布局。
- Bounds的大小改变时,当前视图的中心点不会发生改变,当前视图的大小发生改变,看起来效果就想缩放一样
5、KeyWindown和delegate中的windown的区别
- delegate.window 程序启动时设置的window对象。
- keyWindow 这个属性保存了[windows]数组中的[UIWindow]对象,该对象最近被发送了[makeKeyAndVisible]消息
一般情况下 delegate.window 和 keyWindow 是同一个对象,但不能保证keyWindow就是delegate.window,因为keyWindow会因为makeKeyAndVisible而变化,例如,程序中添加了一个悬浮窗口,这个时候keywindow就会变化。
6、block和delegate的区别
- delegate运行成本低,block的运行成本高
block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除。delegate只是保存了一个对象指针,直接回调,没有额外消耗。就像C的函数指针,只多做了一个查表动作。
- delegate更适用于多个回调方法(3个以上),block则适用于1,2个回调时。
7、为什么Block用copy关键字
Block在没有使用外部变量时,内存存在全局区,然而,当Block在使用外部变量的时候,内存是存在于栈区,当Block copy之后,是存在堆区的。存在于栈区的特点是对象随时有可能被销毁,一旦销毁在调用的时候,就会造成系统的崩溃。所以Block要用copy关键字。
8、KVO的实现原理
KVO 是(Key-valueObserve) Objective-C 对观察者模式(Observer Pattern)的实现。也是 Cocoa Binding 的基础。当被观察对象的某个属性发生更改时,观察者对象会获得通知。
1.iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)
- 利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
- 当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数,这个函数内部调用的方法如下
1.willChangeValueForKey:
2.父类原来的setter
3.didChangeValueForKey:
4.didChangeValueForKey内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)
2.如何手动触发KVO?
- 手动调用willChangeValueForKey:和didChangeValueForKey:
3.直接修改成员变量会触发KVO么?
- 不会触发KVO 因为其内部是重写set方法来达到监听的
9、什么情况使用weak关键字,相比assign有什么不同?
1.什么情况下使用weak?
在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性
自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。
2.不同点
weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。
assign 可以用非 OC 对象,而 weak 必须用于 OC 对象
10、MVC、MVVM、MVP的优缺点
1.MVC:Model-View-Controller
MVC是通过controller的控制去操作model层的数据,并且返回给view层展示。
MVC工作原理:用户触发事件 -- view层发送指令到controller层 -- controller通知model层更新数据 -- 数据更新完显示在view层上
优缺点
优点:
通过controller控制全局,同时将view和model的变化分开,对复杂混乱的项目结构,有了明确的组织方式
缺点:
1.当业务逻辑增加时,大量的逻辑代码放进了controller,导致controller越发臃肿,后期维护成本随之提升
2.没有区分业务逻辑和业务展示,对单元测试不友好
2.MVVM:Model-View-ViewModel
MVVM相对MVP来说将presenter层换成了viewmodel层,并且view层和view model层是相互绑定的关系,也就是当viewmodel层更新时,view层会相应的变动ui。
优缺点
优点:
1.view可以独立于model进行变化和修改,一个viewmodel可以绑定在不同的view上,降低耦合,增加复用。2.不仅解决model和view耦合问题,同时解决了维护两者映射关系的大量繁杂代码和DOM操作代码,提高开发效率、可读性,并保持优越的性能表现
缺点:
1.不适用于简单的项目2.大型的项目视图状态较多时构建和维护成本大
3.MVP:Model-View-Presenter
MVP是MVC的演化,MVC中的model和view两层存在耦合,之间相互依赖过多,由于view可以和model直接通信,造成了view既依赖于controller又依赖于model的局面,controller同样依赖于view和model,耦合性过高。在这种情况下MVP应运而生。
可以看出与MVC不同的是,view层和model层不再相互可知,完全的耦合,presenter充当了桥梁的作用,用于操作view层发出的事件传递到presenter层中,presenter层去操作model层,并将数据返回给view层。
优点:
1.model和view分离,可以做到修改view而不影响model,解决了两者耦合问题2.更加高效的使用model,view不依赖model,view能做到对业务的完全分离
缺点:
presenter中除了处理业务逻辑,还需处理view-model两层的协议,同样会导致presenter层的代码臃肿
11、性能优化-对TableView进行性能优化有哪些方式?
1.cell的重用机制方面优化
2.缓存cell 的高度 把cell的高度放在数据模型里
3.从图层方面来说 少使用subviews,少使用透明度 光栅化 圆角 阴影 等造成离屏渲染的方法
4.按需加载 尽量使用懒加载的方式初始化
5.有些控件的显示与隐藏 用hidden来控制
6.图片使用异步加载的方式 比如SDWebImg
12、什么是GCD ?谈谈你对GCD的理解?
GCD是Grand Central Dispatch的缩写。
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法。在Mac OS X 10.6雪豹中首次推出,并在最近引入到了iOS4.0。
GCD是一个替代诸如NSThread等技术的很高效和强大的技术。GCD完全可以处理诸如数据锁定和资源泄漏等复杂的异步编程问题。
GCD可以完成很多事情,但是这里仅关注在iOS应用中实现多线程所需的一些基础知识。
在开始之前,需要理解是要提供给GCD队列的是代码块,用于在系统或者用户创建的的队列上调度运行。 声明一个队列
13、iOS自动释放池是什么,如何工作
当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。
1、object-c 是通过一种"referring counting"(引用计数)的方式来管理内存的, 对象在开始分配内存(alloc)的时候引用计数为一,以后每当碰到有copy,retain的时候引用计数都会加一, 每当碰到release和autorelease的时候引用计数就会减一,如果此对象的计数变为了0, 就会被系统销毁.
2、NSAutoreleasePool 就是用来做引用计数的管理工作的,这个东西一般不用你管的.
3、autorelease和release没什么区别,只是引用计数减一的时机不同而已,autorelease会在对象的使用真正结束的时候才做引用计数减一.
14、iOS中持久化方式有哪些?
属性列表文件 – NSUserDefaults 的存储,实际是本地生成一个 plist 文件,将所需属性存储在 plist 文件中。
对象归档 – 本地创建文件并写入数据,文件类型不限
SQLite 数据库 – 本地创建数据库文件,进行数据处理
CoreData – 同数据库处理思想相同,但实现方式不同
15、怎样防止指针的越界使用问题?
必须让指针指向一个有效的内存地址,
1、防止数组越界
2、防止向一块内存中拷贝过多的内容
3、防止使用空指针
4、防止改变const修改的指针
5、防止改变指向静态存储区的内容
6、防止两次释放一个指针
7、防止使用野指针.
16、iOS你在项目中用过 runtime 吗
Objective-C 语言是一门动态语言,编译器不需要关心接受消息的对象是何种类型,接收消息的对象问题也要在运行时处理。
pragramming 层面的 runtime 主要体现在以下几个方面:
1.关联对象 Associated Objects
2.消息发送 Messaging
3.消息转发 Message Forwarding
4.方法调配 Method Swizzling
5.“类对象” NSProxy Foundation | Apple Developer Documentation
6.KVC、KVO About Key-Value Coding
17、关于runloop的理解
RunLoop就是控制线程生命周期并接收事件进行处理的机制。 RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统。
1.了解runloop的原理
Runloop原理 简单的说,runloop是一个事件循环的机制,同时能够保活线程.iOS中每个线程都对应一个runloop,主线程的runloop默认开启,其他线程的runloop默认关闭。线程与runloop是一一对应的关系,子线程的runloop会在第一次调用获取当前runloop的方法时创建(类似于懒加载)。
2.runloop的特性
1.主线程的RunLoop在应用启动的时候就会自动创建
2.其他线程则需要在该线程下自己启动
3.不能自己创建RunLoop
4.RunLoop并不是线程安全的,所以需要避免在其他线程上调用当前线程的RunLoop
5.RunLoop负责管理autorelease pools
6.RunLoop负责处理消息事件,即输入源事件和计时器事件
共有 0 条评论