iOS面试题总结

·  阅读 785
  1. KISS,DRY,YAGNI,Law of Demeter

    1. 简单原则(Keep It Simple and Stupid )
      简单是软件设计的目标,简单的代码占用时间少,漏洞少,并且易于修改。
    2. 避免重复原则(DRY – Don’t repeat yourself)
      编程的最基本原则是避免重复。代码之所以要写的好,不要重复某些“信息”,因为需求人员总是要改需求,所以为了减少修改代码的痛苦,我们不能重复任何信息。
    3. 避免创建你不要的代码 Avoid Creating a YAGNI (You aren’t going to need it)
      除非你需要它,否则别创建新功能。
    4. 迪米特法则又叫作最少知识原则(Law of Demeter)
      该代码只和与其有直接关系的部分连接。(比如:该部分继承的类,包含的对象,参数传递的对象等)。迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。
  2. SOLID 原则

    SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)指代了面向对象编程和面向对象设计的五个基本原则。
    依赖反转原则
    高层次的模块不应依赖低层次的模块,他们都应该依赖于抽象。 抽象不应依赖于具体实现,具体实现应依赖抽象。

  3. 面向对象三大特性的理解

    三大特性是:封装,继承,多态
    所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。
    所谓继承是指可以让某个类型的对象获得另一个类型的对象的属性和方法。它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
    所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用,简单地说就是父类指针指向子类对象。

  4. 对响应式编程的理解

  5. 对函数式编程的理解

  6. C 基本数据结构,8 种,分别长度

    64位:
    char : 1个字节
    short: 2个字节
    int :4个字节
    long :4个字节
    long long :8个字节
    float:4个字节
    double:8个字节
    long double:16个字节

  7. enum

    枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月等等。C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。应该说明的是,枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。

  8. struct 占内存的大小

    结构体的大小,是由所有成员空间大小组合而成。

  9. 指针

    指针的本质是有类型的地址。

  10. 什么是 Runtime

    Objective-C 扩展了 C 语言,并加入了面向对象特性和消息传递机制。而这个扩展的核心是一个用 C 和 编译语言写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石。
    高级编程语言想要成为可执行文件需要先编译为汇编语言再汇编为机器语言,但是OC并不能直接编译为汇编语言,而是要先转写为C语言再进行编译和汇编的操作。我们使用OC进行面向对象开发,而C语言是面向过程开发,这就需要将面向对象的类转变为面向过程的结构体,这个过程就是由runtime来实现的。
    Runtime 是 Objective-C 区别于 C 语言这样的静态语言的一个非常重要的特性。对于 C 语言,函数的调用会在编译期就已经决定好,在编译完成后直接顺序执行。但是 OC 是一门动态语言,函数调用变成了消息发送,在编译期不能知道要调用哪个函数。所以 Runtime 解决了如何在运行时期找到调用方法这样的问题。
    instance -> class -> method -> SEL -> IMP -> 实现函数
    实例对象中存放 isa 指针以及实例变量,有 isa 指针可以找到实例对象所属的类对象 (类也是对象,面向对象中一切都是对象),类中存放着实例方法列表,在这个方法列表中 SEL 作为 key,IMP 作为 value。 在编译时期,根据方法名字会生成一个唯一的 Int 标识,这个标识就是 SEL。IMP 其实就是函数指针 指向了最终的函数实现。整个 Runtime 的核心就是 objc_msgSend 函数,通过给类发送 SEL 以传递消息,找到匹配的 IMP 再获取最终的实现。

  11. Runtime 有什么应用?

    1. 方法交换,可以用来捕获系统方法并进行修改,常用来做兼容iOS版本;
    2. 拦截系统自带的方法调用(Swizzle 黑魔法),比如拦截imageNamed:、viewDidLoad、alloc;
    3. 关联对象,动态添加属性,尤其是在分类中;
  12. 什么是 Hash table

  13. NSDictionary 和 NSCache 有什么区别?

    NSCache胜过NSDictionary的之处在于:
    当系统资源将要耗尽时,它可以自动删减缓存。
    NSCache还会先行删减“最久未使用的”(lease recently used)对象。
    NSCache 并不会“拷贝”键,而是会“保留”它。NSCache对象不拷贝键的原因在于:很多时候,键都是有不支持拷贝操作的对象来充当的。因此,NSCache 不会自动拷贝键,所以说,在键不支持拷贝操作的情况下,该类用起来比字典更方便。
    NSCache是线程安全的。而NSDictionary则绝不具备此优势,意思就是:在开发者自己不编写加锁代码的前提下,多个线程便可以同时访问NSCache。

  14. UIButton 的继承链

    UIButton -> UIControl -> UIView -> UIResponder -> NSObject

  1. iOS启动过程

  2. 响应者链。与手势的关系

    iOS触摸事件处理如下:
    • 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件传给main runloop 中的 event source,event source 监听到有事件传入时会唤醒处于休眠状态的main runloop,然后事件被加入到UIApplication管理的事件队列中;
    • UIApplication会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件给应用程序的主窗口(UIWindow)
    • 主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到firstResponder来处理触摸事件 (hitTest:withEvent:其实是UIView的一个方法) hitTest:withEvent:方法大致处理流程是这样的:

    找到firstResponder后, 利用响应者链寻找事件的响应者。该路径开始于firstResponder结束于单例application。事件首先会让firstResponder对象去处理,如果它无法处理则会向其nextResponder对象转发事件。当所有对象都无法处理事件后将最后转发到application处并最终忽略该事件。在UIKit中,UIApplication、UIView、UIViewController这几个类都是直接继承自UIResponder类。因此UIKit中的视图、控件、视图控制器,以及我们自定义的视图及视图控制器都有响应事件的能力。这些对象通常被称为响应对象,是响应链中的一个节点。

  3. UIView 和 CALayer 有什么关系?

    1. 首先UIView可以响应事件,Layer不可以.
      UIKit使用UIResponder作为响应对象,来响应系统传递过来的事件并进行处理。在 UIResponder中定义了处理各种事件和事件传递的接口。 UIApplication、UIViewController、UIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。 CALayer直接继承 NSObject,并没有相应的处理事件的接口。
    2. UIView是CALayer的delegate
    3. UIView主要处理事件,CALayer负责绘制就更好
    4. 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint.
  4. Container ViewController 结构

  5. App 结构

    UIApplication UIWindow UIViewController UIView

  6. 什么是 Runloop?

    RunLoop 就是一个事件处理的循环,用来不停的调度工作以及处理输 入事件。使用 RunLoop 的目的是让你的线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。 runloop 的设计是为了减少 cpu 无谓的空转。

  7. Block

    可以捕获当前作用域外的局部变量的匿名函数。

  8. 为什么要有UIControl?

  9. iOS 中为什么有数据转模型?

  10. OC 中的元类 meta-class 是什么

  11. 什么是自动释放池 autorelease pool

    在MRC中,当我们不再使用一个对象的时候应该将其空间释放,但是有时候我们不知道何时应该将其释放。为了解决这个问题,Objective-C提供了autorelease方法。autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,就会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作,autorelease实际上只是把对release的调用延迟了。

  12. NSError 和 NSException 有什么区别?

    异常和错误是完全不同的两个东西。如果抛出个异常但是你没捕获,那就会crash,但是如果是返回个错误,对外部来说可以随意怎么办,只是告诉你这个调用有错误。也就是说前者对程序的正常运行会有影响,后者主要是给开发者使用的信息,但是不会影响到程序的正常使用和运行。
    NSException
    如果需要指出程序员的错误,则应该使用NSException。例如:一个方法只能接受奇数作为参数,但是程序员在调用该方法时传入了偶数,这时应该抛出异常,以方便程序员解决代码错误。
    NSError
    对于预期错误,如用户错误和设备环境错误,应该使用NSError。例如:一个方法需要读取用户照片,但是没有访问用户相册的权限,这时应该向方法调用者返回一个NSError对象,指出不能执行本次操作的原因。

  13. 用过什么第三方库?AFNetworking,YYModel

    AFNetworking是iOS开发中最常用的第三方开源库之一,它主要用于进行网络请求。AFNetworking主要是对HTTP协议和iOS网络相关库的封装。

  14. NSTimer 如何导致循环引用?

  15. 为什么 NSTimer 时间不准?

  16. 为什么 NSTimer 在列表滑动时会暂停?

分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改