iOS面试知识整理 - Objective-C 语言特性

191 阅读4分钟

Objective-C 语言特性

分类

分类可以做什么

  • 声明私有方法
  • 分解体积庞大的类文件
  • 把framework的私有方法公开

分类的特点

  • 运行时决议
  • 可以为系统类添加分类

分类可以添加那些内容

  • 实例方法
  • 类方法
  • 协议
  • 属性:不是实例变量

分类总结 源码可知悉

分类方法会覆盖原类方法

同名分类方法谁能生效取决于编译顺序

名字相同的分类会引起编译报错

关联对象

怎么给分类添加成员变量

通过关联对象的技术,associate

id objc_getAssociated
​
void objc_setAssociated
​
void objc_removeAssociated

关联对象,关联到哪里去了呢

关联对象有AssociationsManager管理并在AssociationsHashMap存储

所有对象的关联内容都在同一个全局容器中

关联对象的本质.png

扩展

一般用扩展做什么?

  1. 声明私有属性
  2. 声明私有方法
  3. 声明私有成员变量

扩展的特点

  1. 编译时决议
  2. 只以声明的形式存在,多数在宿主中类的.m
  3. 不能为系统类添加扩展

分类和扩展的区别

从特点出发

代理

  • 准确来说是一种软件设计模式
  • iOS中以@protocol形式体现
  • 传递方式一对一

一般声明为weak以规避循环引用

通知

  • 是使用观察者模式来实现的用于跨层传递消息的机制
  • 传递方式是一对多

KVO

  • KVO是key-value Observing的缩写

  • KVO是Objective C对观察者设计模式的又一实现

  • Apple使用了isa混写(isa-swizzling)来实现KVO KVO_isa.png

KVO面试题

  1. 通过KVC设置value能否生效 --- 能生效

  2. 通过成员变量赋值value能否生效 (_value = xx)--- 不能生效

    1. 除非加上willchange和didchange方法
  3. 使用setter方法改变值才能使KVO生效

KVC

KVC是key-value coding的缩写,主要是以下两个方法

  1. valueForKey
  2. setValueForKey

valueForKey 流程

valueForKey流程.png

setValueForKey 流程

setValueForKey流程.png

属性关键字

  1. 读写权限

    1. readOnly
    2. readWrite(默认)
  2. 原子性

    1. atomic(默认)赋值和获取是安全,但是操作(添加、删除)是不一定能保证线程安全的
    2. nonatomic
  3. 引用计数

    1. retain/strong

    2. copy

    3. assign

      1. 基本数据类型 ,int、bool
      2. 修饰对象类型,不改变其引用计数
      3. 移除时,会产生悬垂指针,仍然指向元类对象
    4. weak 弱引用

      1. 不改变被修饰对象的引用计数
      2. 所指对象在被释放之后会自动置为nil

Copy

浅拷贝

浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间

  1. 会增加对象的引用计数
  2. 不会发生新的内存分配

深拷贝

  1. 会产生新的内存分配
  2. 不会增加原对象的引用计数

copy操作.png

  • 可变对象的copy和mutableCopy都是深拷贝
  • 不可变对象的copy是浅拷贝,mutableCopy是深拷贝
  • copy返回的对象都是不可变对象

@property(copy)NSMutableArray *array?会有什么问题

  • 如果赋值过来是NSMutableArray,copy之后是NSArray
  • 如果赋值过来是NSArray,copy之后还是NSArray

面试总结

  1. 简述分类实现原理

    1. 由运行时实现
    2. 最后添加的同名方法会覆盖
  2. KVO的实现原理

    1. 观察者模式的实现
    2. isa 混写,运行时新增了该类的子类,然后重写setter方法,然后重新指向isa
  3. 能否为分类添加成员变量?为什么不可以?如果要,要怎么实现?

    1. 不可以添加成员变量
    2. category 它是在运行期决议的。 因为在运行期即编译完成后,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的。分类里面不能添加Ivar是因为分类本身并不是一个真正的类,它并没有自己的ISA。类最开始生成了很多基本属性,比如IvarList,MethodList,分类只会将自己的method attach到主类,并不会影响到主类的IvarList。这就是为什么分类里面不能增加成员变量的原因。
    3. 关联对象方法可以