iOS 面试基础题
一、Objective-C 基础
- 
问题: Objective-C 的动态特性有哪些?与 Swift 的区别是什么? 答案: - 动态特性:
- 运行时(Runtime):支持方法动态调用(objc_msgSend)、动态添加方法、动态交换方法(method swizzling)。
- KVC/KVO:键值编码和键值观察,动态访问和监听属性。
- Category:运行时扩展类功能。
 
- 与 Swift 的区别:
- Swift 是静态类型语言,编译时优化更好,性能更高。
- Objective-C 依赖运行时,灵活但性能稍逊。
- Swift 的类型安全更强,Optional 避免空指针问题。
 
 
- 动态特性:
- 
问题: 解释 Objective-C 的消息传递机制。 答案: - Objective-C 使用消息传递(message passing)而非直接方法调用。
- 核心函数 objc_msgSend将消息发送给对象,运行时查找实现。
- 示例:[self performSelector:@selector(doSomething) withObject:nil]; 
- 注意:
- 若方法不存在,可能导致崩溃(unrecognized selector)。
- 使用 respondsToSelector:检查方法存在性。
 
- 若方法不存在,可能导致崩溃(
 
- 
问题: Objective-C 中的属性(@property)有哪些常见修饰符? 答案: - 原子性:atomic(默认,线程安全但性能低)、nonatomic(非线程安全,性能高)。
- 内存管理:strong(持有引用)、weak(弱引用)、copy(复制对象)、assign(基本类型或弱引用)。
- 读写:readonly、readwrite(默认)。
- 示例:@property (nonatomic, strong) NSString *name; 
 @property (nonatomic, weak) id<Delegate> delegate;
 
- 原子性:
- 
问题: Objective-C 中 block 的定义和使用? 答案: - 定义:类似 Swift 闭包,捕获上下文变量。
- 语法:void (^myBlock)(int) = ^(int value) { 
 NSLog(@"Value: %d", value);
 };
 myBlock(42);
- 注意:
- block 捕获变量默认是值捕获,需用 __block修饰变量以支持修改。
- 避免循环引用,使用 __weak typeof(self) weakSelf = self。
 
- block 捕获变量默认是值捕获,需用 
 
二、Swift 基础
- 
问题: Swift 中 struct 和 class 的主要区别是什么? 答案: - 值类型 vs 引用类型: struct 是值类型,复制时创建新副本;class 是引用类型,复制时共享同一实例。
- 继承: class 支持继承,struct 不支持。
- 内存管理: struct 通常在栈上分配,class 在堆上分配,需 ARC 管理。
- 初始化: struct 自动生成成员初始化器,class 需手动定义。
- 可变性: struct 的 mutating 方法需显式声明,class 方法默认可修改实例。
- 使用场景: struct 适合简单数据模型(如 DTO),class 适合复杂对象(如视图控制器)。
 
- 
问题: struct 和 class 在初始化时,属性和 init 函数有哪些注意事项? 答案: - 属性初始化:
- 非可选属性必须在初始化时赋值,或提供默认值。
- 常量(let)属性只能在初始化时赋值。
- struct 自动生成成员初始化器(若无自定义 init),class 需显式定义。
 
- init 函数:
- class 的 init 需确保所有非可选属性初始化完成。
- class 支持指定初始化器(designated)和便利初始化器(convenience),convenience 必须调用 designated。
- struct 的 init 不需要考虑继承,但若自定义 init,自动生成的成员初始化器失效。
- deinit 仅适用于 class,用于释放资源。
 
- 示例:class Animal { 
 var name: String
 init(name: String) { self.name = name }
 }
 struct Point {
 var x: Int, y: Int
 // 自动生成 init(x:y:)
 }
 
- 属性初始化:
- 
问题: class 是否可以服从 Codable 协议?如何实现? 答案: - 是的,class 可以服从 Codable 协议(包括 Encodable 和 Decodable)。
- 实现方式:
- 确保 class 的所有存储属性都符合 Codable。
- 若属性是自定义类型,自定义类型也需符合 Codable。
- 示例:class User: Codable { 
 var name: String
 var age: Int
 }
 
- 注意:class 的继承需要额外处理,父类和子类都需符合 Codable,可能需自定义编码/解码逻辑。
 
- 
问题: 如何利用 Codable 协议兼容接口下发的字段类型或字段名? 答案: - 兼容字段名:
- 使用 CodingKeys枚举映射接口字段名和 Swift 属性名。
- 示例:struct User: Codable { 
 var userName: String
 var userAge: Int
 
 enum CodingKeys: String, CodingKey {
 case userName = "name"
 case userAge = "age"
 }
 }
 
- 使用 
- 兼容字段类型:
- 自定义 init(from:)和encode(to:)方法处理类型转换。
- 示例(处理 age 可能是 String 或 Int):struct User: Codable { 
 var name: String
 var age: Int
 
 enum CodingKeys: String, CodingKey {
 case name, age
 }
 
 init(from decoder: Decoder) throws {
 let container = try decoder.container(keyedBy: CodingKeys.self)
 name = try container.decode(String.self, forKey: .name)
 if let ageInt = try? container.decode(Int.self, forKey: .age) {
 age = ageInt
 } else if let ageString = try? container.decode(String.self, forKey: .age) {
 age = Int(ageString) ?? 0
 } else {
 age = 0
 }
 }
 }
 
- 自定义 
 
- 兼容字段名:
- 
问题: Optional 的本质是什么? 答案: - Optional 是一个枚举类型,定义如下:enum Optional<Wrapped> { 
 case none
 case some(Wrapped)
 }
- 本质:
- 表示一个值可能存在(some)或不存在(none)。
- 提供安全的方式处理空值,避免运行时崩溃。
 
- 使用场景:
- 解包:if let,guard let,??,map,flatMap。
- 链式调用:optional?.property?.method()。
 
- 解包:
- 注意:
- 避免强制解包(!),除非确定值存在。
 
- 避免强制解包(
 
- Optional 是一个枚举类型,定义如下:
- 
问题: 解释 Swift 中的 GCD 多线程编程及其常见用法。 答案: - GCD(Grand Central Dispatch):
- 苹果提供的并发框架,用于管理任务队列和线程。
- 核心概念:DispatchQueue(串行/并发)、DispatchGroup、DispatchSemaphore。
 
- 常见用法:
- 异步任务:DispatchQueue.global().async { 
 // 后台任务
 DispatchQueue.main.async {
 // 更新 UI
 }
 }
- 串行队列:let serialQueue = DispatchQueue(label: "com.example.serial") 
 serialQueue.async { /* 任务 1 */ }
 serialQueue.async { /* 任务 2 */ } // 按顺序执行
- DispatchGroup:let group = DispatchGroup() 
 group.enter()
 DispatchQueue.global().async {
 // 任务 1
 group.leave()
 }
 group.notify(queue: .main) {
 // 所有任务完成
 }
 
- 异步任务:
- 注意:
- 避免在主线程执行耗时任务。
- 合理使用 QoS(服务质量)优先级。
 
 
- GCD(Grand Central Dispatch):
- 
问题: 解释 Swift 的 Task 和 async/await 多线程编程。 答案: - async/await:
- Swift 5.5 引入的结构化并发模型,简化异步编程。
- 使用 async标记异步函数,await暂停等待结果。
 
- Task:
- 用于启动异步任务,运行于并发上下文。
- 示例:func fetchData() async throws -> Data { 
 let url = URL(string: "https://example.com")!
 let (data, _) = try await URLSession.shared.data(from: url)
 return data
 }
 Task {
 do {
 let data = try await fetchData()
 print("Data fetched")
 } catch {
 print("Error: \(error)")
 }
 }
 
- 并发模型:
- Task Group:并行执行多个任务。let result = try await withTaskGroup(of: Int.self) { group in 
 for i in 0..<5 {
 group.addTask { return i * 2 }
 }
 var results: [Int] = []
 for try await value in group {
 results.append(value)
 }
 return results
 }
- Actor:线程安全的引用类型,避免数据竞争。actor Counter { 
 var value = 0
 func increment() { value += 1 }
 }
 
- Task Group:并行执行多个任务。
 
- async/await:
- 
问题: Swift 中的闭包、逃逸闭包和捕获列表? 答案: - 闭包定义:
- 自包含的代码块,可捕获上下文变量。
- 语法:{ (parameters) -> ReturnType in statements }
 
- 捕获列表:
- 控制闭包如何捕获变量(值/引用)。
- 示例:var x = 10 
 let closure = { [x] in print(x) } // 捕获 x 的值
 x = 20
 closure() // 输出 10
 
- 逃逸闭包:
- 闭包在函数返回后仍可被调用,需标记 @escaping。
- 示例:var completion: (() -> Void)? 
 func performTask(completion: @escaping () -> Void) {
 self.completion = completion
 }
 
- 闭包在函数返回后仍可被调用,需标记 
 
- 闭包定义:
- 
问题: 高阶函数(如 map、filter、reduce)的用途和示例? 答案: - 用途:
- 函数式编程核心,用于处理集合数据。
- 提高代码简洁性和可读性。
 
- 示例:
- map:let numbers = [1, 2, 3] 
 let doubled = numbers.map { $0 * 2 } // [2, 4, 6]
- filter:let evens = numbers.filter { $0 % 2 == 0 } // [2] 
- reduce:let sum = numbers.reduce(0) { $0 + $1 } // 6 
 
- map:
 
- 用途:
- 
问题: Combine 框架的核心概念和使用场景? 答案: - 核心概念:
- 响应式编程框架,处理异步事件流。
- 核心组件:Publisher、Subscriber、Operator。
 
- 使用场景:
- 网络请求、 Connor输入、状态变化。
 
- 示例:import Combine 
 let publisher = [1, 2, 3].publisher
 let cancellable = publisher
 .map { $0 * 2 }
 .sink { print($0) } // 输出 2, 4, 6
- 注意:
- 使用 AnyCancellable管理订阅生命周期。
 
- 使用 
 
- 核心概念:
- 
问题: RxSwift 的核心概念和与 Combine 的区别? 答案: - 核心概念:
- 基于观察者模式的响应式框架。
- 核心组件:Observable、Observer、Operator、Scheduler。
 
- 示例:import RxSwift 
 let disposeBag = DisposeBag()
 Observable.just([1, 2, 3])
 .map { $0 * 2 }
 .subscribe(onNext: { print($0) })
 .disposed(by: disposeBag)
- 与 Combine 的区别:
- Combine 是苹果原生框架,RxSwift 是第三方库。
- Combine 集成 Swift 特性(如 property wrapper)。
- RxSwift 社区更大,跨平台支持更好。
 
 
- 核心概念:
- 
问题: ARC 内存管理的原理和常见问题? 答案: - 原理:
- 自动引用计数(ARC)跟踪对象引用,引用计数为 0 时释放。
- 强引用(strong)、弱引用(weak)、无主引用(unowned)。
 
- 常见问题:
- 循环引用:
- 两个对象互相强引用,导致内存泄漏。
- 解决:使用 weak 或 unowned。
- 示例:class Person { 
 var dog: Dog?
 }
 class Dog {
 weak var owner: Person? // 避免循环引用
 }
 
- 闭包捕获:
- 闭包捕获 self 可能导致循环引用。
- 解决:使用 [weak self]。
 
 
- 循环引用:
 
- 原理:
三、iOS 开发基础
- 
问题: 什么是 UIApplication 和 UIApplicationDelegate? 答案: - UIApplication:管理 iOS 应用的生命周期和全局状态(如通知、后台任务)。
- UIApplicationDelegate:处理应用生命周期事件(如 didFinishLaunchingWithOptions、applicationDidEnterBackground)。
- 示例:class AppDelegate: UIResponder, UIApplicationDelegate { 
 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
 return true
 }
 }
 
- 
问题: 解释 UIViewController 的生命周期。 答案: - viewDidLoad:视图加载完成,初始化 UI。
- viewWillAppear:视图即将显示。
- viewDidAppear:视图已显示。
- viewWillDisappear:视图即将消失。
- viewDidDisappear:视图已消失。
- 注意:避免在 viewDidLoad 执行耗时任务,UI 更新放在 viewWillAppear 或 viewDidAppear。
 
- 
问题: Auto Layout 的基本原理和使用方式? 答案: - 原理:通过约束(constraints)定义视图的布局,适应不同屏幕大小。
- 使用方式:
- Interface Builder:拖拽设置约束。
- 代码:NSLayoutConstraint 或 Anchor API。
- 示例(Anchor):view.translatesAutoresizingMaskIntoConstraints = false 
 NSLayoutConstraint.activate([
 view.topAnchor.constraint(equalTo: superview.topAnchor, constant: 20),
 view.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: 20)
 ])
 
 
四、内存管理
- 
问题: MRC 和 ARC 的区别? 答案: - MRC(手动引用计数):
- 开发者手动调用 retain、release、autorelease。
- 繁琐,易出错。
 
- ARC(自动引用计数):
- 编译器自动插入内存管理代码。
- 简化开发,但需注意循环引用。
 
- 注意:MRC 已基本淘汰,iOS 5 后默认 ARC。
 
- MRC(手动引用计数):
- 
问题: 如何检测和解决内存泄漏? 答案: - 检测:
- 使用 Instruments 的 Leaks 工具。
- 分析对象引用计数。
 
- 解决:
- 使用 weak/unowned 打破循环引用。
- 确保 delegate 属性使用 weak。
- 检查闭包/block 中的 self 捕获。
 
 
- 检测:
五、多线程
- 
问题: iOS 中有哪些多线程技术? answers: - GCD:DispatchQueue 管理任务队列。
- NSOperation/OperationQueue:高级封装,支持依赖和取消。
- Thread:底层线程管理(不推荐)。
- async/await(Swift):结构化并发,简化异步编程。
- NSTimer/PThread:特定场景(如定时器、低级线程)。
 
- 
问题: 主线程和全局线程的区别?如何确保 UI 更新在主线程? 答案: - 主线程:处理 UI 和用户交互,阻塞会导致卡顿。
- 全局线程:用于后台任务,如网络请求、数据处理。
- 确保主线程:
- GCD:DispatchQueue.main.async { /* UI 更新 */ }
- async/await:@MainActor或Task { await MainActor.run { /* UI 更新 */ } }
 
- GCD:
 
六、设计模式
- 
问题: iOS 开发中常用的设计模式有哪些? 答案: - 单例:如 UIApplication.shared。
- 委托(Delegate):如 UITableViewDelegate。
- 观察者:如 KVO 或 NotificationCenter。
- MVC:Model-View-Controller,iOS 默认架构。
- MVVM:结合 Combine/RxSwift 实现响应式架构。
- 工厂模式:创建对象(如 URLSessionConfiguration)。
- 适配器:桥接不同接口(如第三方库适配)。
 
- 
问题: 实现一个简单的单例模式(Swift 和 Objective-C)。 答案: - Swift:class Singleton { 
 static let shared = Singleton()
 private init() {}
 }
- Objective-C:@interface Singleton : NSObject 
 + (instancetype)shared;
 @end
 @implementation Singleton
 + (instancetype)shared {
 static Singleton *instance = nil;
 static dispatch_once_t onceToken;
 dispatch_once(&onceToken, ^{
 instance = [[Singleton alloc] init];
 });
 return instance;
 }
 @end
 
- Swift:
七、网络
- 
问题: iOS 中如何进行网络请求? 答案: - URLSession:
- 默认方式,支持 GET、POST、上传、下载。
- 示例(Swift):let url = URL(string: "https://api.example.com")! 
 let task = URLSession.shared.dataTask(with: url) { data, response, error in
 guard let data = data, error == nil else { return }
 // 处理数据
 }
 task.resume()
 
- Alamofire(第三方库):
- 简化请求和响应处理。
- 示例:import Alamofire 
 AF.request("https://api.example.com").responseJSON { response in
 // 处理响应
 }
 
 
- URLSession:
- 
问题: 如何处理 HTTPS 和证书验证? 答案: - 默认 HTTPS:URLSession 默认支持 HTTPS。
- 自定义证书验证:
- 实现 URLSessionDelegate的didReceiveChallenge方法。
- 示例:class NetworkManager: NSObject, URLSessionDelegate { 
 func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
 // 验证服务器证书
 completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
 }
 }
 
- 实现 
 
八、数据库
- 
问题: iOS 中常见的数据库技术有哪些? 答案: - Core Data:
- 苹果原生框架,对象-关系映射(ORM)。
- 适合复杂数据模型。
 
- Realm:
- 第三方数据库,性能高,易用。
- 支持实时更新。
 
- SQLite:
- 轻量级数据库,需手动管理 SQL。
- 使用 FMDB 简化操作。
 
- UserDefaults:
- 轻量级键值存储,适合简单数据。
 
 
- Core Data:
- 
问题: Core Data 的基本使用流程? 答案: - 步骤:
- 创建数据模型(.xcdatamodeld 文件)。
- 配置 NSPersistentContainer。
- 执行 CRUD 操作。
 
- 示例:let container = NSPersistentContainer(name: "Model") 
 container.loadPersistentStores { _, error in
 guard error == nil else { return }
 let context = container.viewContext
 let entity = NSEntityDescription.insertNewObject(forEntityName: "User", into: context)
 entity.setValue("John", forKey: "name")
 try? context.save()
 }
 
- 步骤:
九、框架
- 
问题: UIKit 和 SwiftUI 的区别和适用场景? 答案: - UIKit:
- 基于命令式编程,成熟稳定。
- 适合复杂应用,支持 iOS 9+。
- 使用 UIViewController、UIView 等。
 
- SwiftUI:
- 基于声明式编程,简洁现代。
- 适合新项目,iOS 13+。
- 使用 View 协议和 Combine。
 
- 选择:
- UIKit:兼容旧设备或需要复杂自定义。
- SwiftUI:快速开发,跨平台(iOS、macOS)。
 
 
- UIKit:
- 
问题: 如何在 UIKit 中集成 SwiftUI? 答案: - 使用 UIHostingController嵌入 SwiftUI 视图。
- 示例:import SwiftUI 
 let swiftUIView = Text("Hello, SwiftUI!")
 let hostingController = UIHostingController(rootView: swiftUIView)
 navigationController?.pushViewController(hostingController, animated: true)
 
- 使用 
十、综合问题
- 
问题: 设计一个线程安全的网络请求单例类,支持 Codable(Swift)。 答案: import Foundation 
 final class NetworkManager: Codable {
 static let shared = NetworkManager()
 private let urlSession = URLSession.shared
 
 private init() {}
 
 enum CodingKeys: CodingKey {
 case dummy
 }
 
 func encode(to encoder: Encoder) throws {
 var container = encoder.container(keyedBy: CodingKeys.self)
 // 编码逻辑
 }
 
 init(from decoder: Decoder) throws {
 // 单例无需恢复实例
 }
 
 func fetchData<T: Decodable>(from url: URL) async throws -> T {
 let (data, _) = try await urlSession.data(from: url)
 return try JSONDecoder().decode(T.self, from: data)
 }
 }
- 
问题: 如何优化 iOS 应用的性能? 答案: - 内存:避免循环引用,使用 Instruments 检测泄漏。
- CPU:减少复杂计算,使用 GCD 或 async/await 优化耗时任务。
- UI:异步加载图片,优化 Auto Layout,减少离屏渲染。
- 网络:缓存响应,压缩数据,使用分页加载。
- 启动时间:延迟非必要初始化,主线程只处理 UI。
 
- 
问题: 常见崩溃原因及解决方法? 答案: - 原因:
- 空指针(Objective-C)/强制解包(Swift)。
- 数组越界。
- 主线程阻塞。
- 循环引用导致内存不足。
 
- 解决:
- 使用 Optional 和安全解包。
- 检查数组索引。
- 耗时任务移至后台线程。
- 使用 weak/unowned 打破循环引用。
 
 
- 原因:
 
          