第3章 OC/Swift语言基础:内存管理、属性关键字、KVO/KVC、Block循环引用
本章聚焦:iOS面试必考语言底层机制,涵盖引用计数、ARC、属性修饰符、KVO/KVC原理及Block循环引用。掌握这些知识点能应对80%的OC/Swift基础面试题。
知识结构:属性关键字对比
| 关键字 | 作用 | 使用场景 | 注意点 |
|---|---|---|---|
| strong | 强引用,增加引用计数 | OC对象属性 | 避免循环引用 |
| weak | 弱引用,不增加计数 | delegate、IBOutlets | 对象释放后自动置nil |
| copy | 拷贝一个不可变副本 | NSString、NSArray等 | 避免可变对象被意外修改 |
| assign | 直接赋值,不管理内存 | 基本数据类型(int, float) | 不能用于OC对象,否则野指针 |
| readwrite | 生成getter/setter | 默认属性 | 可被外部读写 |
| readonly | 只读,只生成getter | 对外暴露不可修改属性 | 内部可通过ivar修改 |
面试问答卡片
🎯 面试问题1:谈谈iOS内存管理机制及循环引用问题
考察点:基础理解深度、ARC实现细节、能否识别并解决循环引用。
回答框架:
- 简述引用计数 + ARC 自动管理
- 解释循环引用产生条件(互相强引用、Block捕获self)
- 解决方法:weak、unowned、解除捕获
- 举一个delegate或Block的典型例子
示例回答:
“iOS内存管理基于引用计数,ARC自动插入retain/release。循环引用指两个对象互相强持有导致无法释放,例如A强引用B,B强引用A。解决方法是使用weak或无主引用打破链条,Block中需用weakSelf避免持有self。”
可能追问:
- ARC和MRC的本质区别?
- weak属性在释放时如何nil?
- Swift中循环引用如何避免?([weak self]/[unowned self])
⚠️ 避坑提醒:不要只说“用weak就行”,要说明为什么weak不会增加计数;同时区分weak和unowned(unowned需确保对象未释放)。
🎯 面试问题2:请解释@property属性关键字(如strong、weak、copy)及其使用场景
考察点:内存语义理解、属性修饰符选择依据、可变/不可变对象处理。
回答框架:
- 分三类:线程安全(atomic/nonatomic)、读写(readonly/readwrite)、内存管理(strong/weak/copy/assign)
- 重点对比copy与strong:copy确保不可变拷贝,防止可变对象被修改
- 适用场景:NSString用copy,delegate用weak,基本类型用assign
示例回答:
“strong强持有对象增加计数;weak弱引用不增加,对象释放自动nil;copy拷贝不可变副本,常用NSString防外部修改;assign只用于基本类型,若用于对象会产生野指针。atomic安全但性能低,iOS开发通常用nonatomic。”
可能追问:
- NSMutableString用copy会怎样?
- @property(“copy”) NSString 和 NSString *str; 赋值时底层发生了什么?
- Swift中的strong/weak对应什么?
⚠️ 避坑提醒:很多候选人忽略“copy修饰NSMutableString后赋值结果变为不可变”这一细节,面试官常借此深挖。
🎯 面试问题3:KVO/KVC原理及Block循环引用的避免方式
考察点:动态性理解、KVO观察机制、Block内存捕获及循环引用成因。
回答框架:
- KVO:isa-swizzling + 重写setter方法,观察者模式
- KVC:运行时通过key访问属性,调用setValue:forKey:
- Block循环引用:Block捕获self,导致self -> block -> self 强引用链
- 解决方案:weakSelf + strongSelf(执行时保活),或使用__block并在Block中置nil
示例回答:
“KVO利用runtime动态创建子类并重写setter,KVC通过名称自动查找ivar。Block循环引用常见于属性持有Block且Block内使用了self;标准做法是__weak typeof(self) weakSelf = self,执行时再转强引用避免中途释放。”
可能追问:
- KVO如何手动触发?(willChangeValueForKey / didChangeValueForKey)
- KVC取值顺序(getKey → key.is... → 直接访问ivar)
- Swift中Block(闭包)循环引用如何标记?
⚠️ 避坑提醒:KVO不自动监听容器类内部元素变化;Block循环引用中若使用weakSelf+strongSelf,需确保strongSelf非空判断。
💡 面试加分提醒:以上三个问题是OC/Swift基础面试的“必考三件套”。建议结合项目实战举例(如:项目中遇到过delegate循环引用、KVO未移除导致崩溃等)更能体现经验深度。