1.copy
和strong
修饰符的区别?为何NSString常用copy
?
答案:
strong
增加引用计数,copy
创建不可变副本。NSString用copy
防止外部可变字符串(如NSMutableString)修改导致值变化,保障数据不可变性。
2.GCD与NSOperation的适用场景?如何实现任务依赖和优先级控制?
答案:GCD适合简单任务(如异步加载),NSOperation适合复杂任务(支持取消、依赖、优先级)。通过
addDependency
设置依赖,queuePriority
控制优先级。
3.Runtime的消息转发机制分哪几步?如何动态添加方法?
答案:消息转发分为:
动态方法解析(
resolveInstanceMethod:
);备用接收者(
forwardingTargetForSelector:
);完整转发(
methodSignatureForSelector:
和forwardInvocation:
)。
动态添加方法使用class_addMethod
。
4.如何优化UITableView滚动性能?
答案:
复用Cell(
dequeueReusableCellWithIdentifier:
);异步解码图片、离屏渲染(如使用
CATiledLayer
);减少AutoLayout计算,预计算Cell高度;
使用
willDisplayCell
延迟加载非关键资源。
5.Block的循环引用如何产生?如何用__weak和__block解决?
答案:Block捕获外部对象强引用导致循环。解决:
使用
__weak
弱引用(如__weak typeof(self) weakSelf = self
);
__block
修饰变量并在Block内手动置nil(需调用Block)。
6. Swift与Objective-C的Runtime消息转发机制对比
问题:Objective-C的消息转发分为
resolveInstanceMethod
、forwardingTargetForSelector
、methodSignatureForSelector
三阶段,而Swift中@dynamic
修饰的方法如何实现类似机制?请结合Swift的Method Dispatch机制分析。
深度解析:
1.Objective-C的消息转发流程:
-
动态方法解析:
resolveInstanceMethod
允许运行时添加方法实现。 -
快速转发:
forwardingTargetForSelector
将消息转发给其他对象处理。 -
完整转发:
methodSignatureForSelector
和forwardInvocation
构造NSInvocation对象。
2.Swift的动态性限制:
Swift默认使用静态派发(值类型)或虚表派发(类),除非:
-
使用
@dynamic
修饰符(如CoreData的NSManagedObject子类)。 -
继承自NSObject并标记
@objc dynamic
。
3.Swift中的消息转发实现:
class MyClass: NSObject {
@objc dynamic func handleMessage() { /* 默认实现 */ }
}
let obj = MyClass()
// 替换方法实现
let originalMethod = class_getInstanceMethod(MyClass.self, #selector(handleMessage))
let newMethod = class_getInstanceMethod(MyClass.self, #selector(newHandleMessage))
method_exchangeImplementations(originalMethod, newMethod)
面试延伸:
-
Swift如何实现KVO?答:通过
@objc dynamic
强制使用Objective-C Runtime。 -
Swift的协议扩展(Protocol Extension)是否支持动态派发?答:协议扩展方法静态派发,除非在协议中声明为
@objc
。
7.Swift Concurrency(async/await)与GCD的底层线程管理对比
问题:Swift的async/await语法在底层如何管理线程?与GCD的Work Item和队列优先级有何本质区别?
深度解析:
1.GCD的线程管理:
-
基于线程池和队列(Serial/Concurrent),通过优先级(QoS)调度任务。
-
问题:优先级反转(Priority Inversion)、线程爆炸(Thread Explosion)。
2.Swift Concurrency模型:
-
协作式线程池:由系统管理的线程池(默认线程数=CPU核心数),任务通过挂起(Suspend)而非阻塞(Block)让出线程。
-
结构化并发:通过
TaskGroup
和async let
绑定子任务生命周期。 -
优先级继承:子任务自动继承父任务优先级,避免优先级反转。
3.性能对比:
// GCD
DispatchQueue.global(qos: .userInitiated).async {
let data = fetchData()
DispatchQueue.main.async { updateUI(data) }
}
// Swift Concurrency
Task(priority: .userInitiated) {
let data = await fetchData()
await MainActor.run { updateUI(data) }
}
-
优势:更少线程切换、自动取消传播、无回调地狱。
面试延伸:
-
MainActor
与DispatchQueue.main
的区别?答:MainActor
是全局串行执行器,整合了Swift Concurrency的调度机制。 -
如何避免Task的循环引用?答:使用
[weak self]
捕获列表或Task.detached
。
8. Swift Actor模型与GCD线程调度的性能对比及死锁预防
问题:Swift的Actor如何通过隔离状态保证线程安全?对比GCD的串行队列,分析两者在10k任务并发下的性能差异。
深度解析:
-
Actor机制:每个Actor独立串行队列,通过
await
挂起非阻塞任务。 -
性能对比:
指标 Swift Actor GCD串行队列 上下文切换开销 低(协作式) 高(线程切换) 死锁风险 低(编译器静态检查) 高(需手动避免) 内存占用 更优(少量Continuation) 线程栈积累 -
死锁案例:
actor A {
func foo() async { await bar() }
func bar() async { ... }
}
// 无死锁,编译器强制异步调用
9.Objective-C与Swift混编下的内存管理陷阱
问题:在Swift中调用Objective-C的
retain
/release
方法会导致什么问题?如何通过Unmanaged
正确转换Core Foundation对象?
深度解析:
-
陷阱场景:Swift的ARC自动插入
retain
/release
,手动调用会导致重复释放。 -
安全转换:
let cfStr = CFStringCreateWithCString(nil, "test", kCFStringEncodingUTF8)
let swiftStr = Unmanaged<CFString>.fromOpaque(cfStr).takeRetainedValue()
- 调试工具:Xcode的Memory Graph可检测野指针和循环引用.
10.Metal API在实时滤镜渲染中的优化策略
问题:如何通过Metal的
MTLHeap
和MTLFence
实现纹理内存的高效复用?对比Core Image的性能瓶颈。
深度解析:
-
MTLHeap优化:预分配GPU内存池,避免频繁申请释放。
-
MTLFence应用:同步GPU指令队列,防止资源竞争。
-
对比Core Image:
-
Metal:延迟<5ms,支持自定义Shader。
-
Core Image:延迟15-30ms,但API更简洁。
-
实战建议:
混合使用Core Image预处理和Metal后处理。
11.LLVM编译优化对Swift协议扩展方法派发的影响
问题:分析Swift协议扩展方法在O2优化下的静态派发机制,如何通过
@objc dynamic
强制改为动态派发?
深度解析:
-
静态派发条件:方法未在协议声明中定义,直接通过扩展实现。
-
动态派发实现:
@objc protocol MyProtocol {}
extension MyProtocol {
@objc dynamic func foo() { ... }
}
-
性能代价:动态派发增加方法查找开销约20%。
12.基于Combine框架的响应式状态管理设计模式
问题:在SwiftUI中如何通过Combine的
@Published
和CurrentValueSubject
实现跨View共享状态?对比RxSwift的内存泄漏风险。
深度解析:
- 状态共享方案:
class Store: ObservableObject {
@Published var state = AppState()
private let subject = CurrentValueSubject<AppState, Never>(AppState())
}
-
内存安全:
-
Combine自动管理订阅生命周期。
-
RxSwift需手动
dispose()
,易遗漏导致泄漏。
-
最佳实践:
结合weak self
与.store(in: &cancellables)
。
扩展建议
- 研究Swift Concurrency(async/await)与GCD的性能对比,分析线程管理的最佳实践。
- 掌握Swift Concurrency的底层原理(如Continuation、Actor模型),对比Objective-C Runtime的历史局限性。
- 深入Instrument的Time Profiler定制化分析技巧,优化冷启动时间。
持续更新中。。。