一、 单选题****
- 以下哪个是Objective-C的动态特性?
A. 静态类型
B. 方法调用时的动态绑定
C. 编译时确定方法实现
D. 不支持运行时修改类结构
答案:B
解析:Objective-C通过Runtime实现动态方法绑定,运行时通过objc_msgSend动态查找方法实现。
- 以下哪个是Objective-C的Runtime特性?
A. 可以在运行时动态添加方法
B. 可以在编译时修改类结构
C. 不支持动态消息转发
D. 无法交换方法实现
答案:A
解析:Runtime允许动态添加方法、交换方法实现、动态消息转发等。
- 在Swift中,@escaping关键字的作用是?
A. 标记闭包不逃逸当前作用域
B. 标记闭包逃逸当前作用域
C. 强制闭包同步执行
D. 禁止闭包捕获外部变量
答案:B
解析:@escaping表示闭包可能逃逸当前作用域(如异步回调)。
- 以下哪个不是iOS的内存管理机制?
A. ARC
B. MRC
C. 引用计数
D. 垃圾回收
答案:D
解析:iOS使用ARC(自动引用计数)和MRC(手动引用计数),无垃圾回收机制。
- 在Objective-C中,@property的nonatomic属性表示?
A. 线程安全
B. 非原子性访问,性能更高
C. 自动合成getter/setter
D. 不生成ivar
答案:B
解析:nonatomic不保证线程安全,但性能更高;atomic保证线程安全。
- 在Swift中,defer语句的作用是?
A. 延迟执行代码
B. 在函数返回后执行
C. 在异常抛出后执行
D. 在循环结束后执行
答案:B
解析:defer中的代码会在当前作用域结束时(如函数返回)执行。
7.下列代码的执行输出结果是?
func testDefer() {
defer {
print("方法中defer内容")
}
if true {
defer {
print("if 中defer内容")
}
print("if中最后的代码")
}
print("方法中的代码")
if true {
return
}
print("方法结束前最后一句代码")
}
A.
if中最后的代码
if 中defer内容
方法中的代码
方法中defer内容
B.
if中最后的代码
方法中的代码
if 中defer内容
方法中defer内容
C.
if中最后的代码
if 中defer内容
方法中的代码
方法中defer内容
方法结束前最后一句代码
D.
if中最后的代码
方法中的代码
方法中defer内容
if 中defer内容
答案:A
解析:defer中的代码会在当前作用域结束时(如函数返回)执行。
- 以下哪个是Objective-C的关联对象(Associated Object)的作用?
A. 动态添加属性
B. 修改类方法
C. 实现多重继承
D. 替代KVO
答案:A
解析:关联对象用于动态给类添加属性,常用于Category扩展。
- 在Swift中,guard语句的作用是?
A. 替代if语句
B. 提前退出作用域
C. 捕获异常
D. 强制解包
答案:B
解析:guard用于提前退出作用域(如函数、循环),常用于条件判断。
- 以下哪个是Objective-C的弱引用关键字?
A. __weak
B. __strong
C. __unsafe_unretained
D. 以上都是
答案:A
解析:__weak用于弱引用,避免循环强引用。
- 在Swift中,@autoclosure的作用是?
A. 自动闭包
B. 延迟执行
C. 强制解包
D. 以上都是
答案:A
解析:@autoclosure将表达式转换为闭包,延迟执行。
- 在Swift中,@discardableResult的作用是?
A. 忽略返回值
B. 强制使用返回值
C. 标记结果可丢弃
D. 以上都是
答案:A
解析:@discardableResult允许忽略函数返回值,避免编译警告。
- 以下哪个是Objective-C的动态消息转发机制?
A. resolveInstanceMethod:
B. forwardingTargetForSelector:
C. methodSignatureForSelector:
D. 以上都是
答案:D
解析:动态消息转发通过这三个方法实现。
- 在Swift中,@objc的作用是?
A. 允许Objective-C调用
B. 强制解包
C. 标记私有属性
D. 以上都是
答案:A
解析:@objc用于暴露Swift代码给Objective-C。
15.关于Swift结构体(Struct)和类(Class)的区别,错误的是:
A. 结构体是值类型,类是引用类型
B. 类支持继承,结构体不支持
C. 结构体可以有析构器(deinit)
D. 类可以被多次引用,结构体赋值时会发生拷贝
答案:C
16. UIViewController的生命周期中,哪个方法只调用一次,适合做一次性初始化工作?
A. viewWillAppear
B. viewDidLoad
C. viewDidAppear
D. loadView
答案:B
17. 关于iOS的响应者链(Responder Chain),以下描述错误的是:
A. UIResponder是所有响应者对象的基类
B. 事件将沿着响应者链向上传递,直到被处理
C. 如果一个View不处理事件,它会将事件传递给它的父视图
D. 响应者链的顶端是UIWindow
答案:D
18. UITableView的重用机制是为了解决:
A. 滑动流畅性问题
B. 内存占用过高问题
C. 数据和视图同步问题
D. A和B
答案:D
19. 以下哪种情况会触发离屏渲染(Offscreen Rendering)?
A. 设置layer.cornerRadius
B. 设置layer.cornerRadius且layer.masksToBounds = true
C. 设置backgroundColor
D. 设置frame
答案:B
20. Grand Central Dispatch (GCD) 中,哪个队列的优先级最高?
A. DispatchQueue.main
B. DispatchQueue.global(qos:.background)
C. DispatchQueue.global(qos: .userInteractive)
D. DispatchQueue.global(qos: .utility)
答案:C
21. 在GCD中,如何向全局并发队列提交一个异步任务?
A. DispatchQueue.main.async { … }
B. DispatchQueue.sync { … }
C. DispatchQueue.global().async { … }
D. DispatchQueue.serial().async { … }
答案:C
22. 关于Operation和OperationQueue,以下说法正确的是:
A. 它们是基于GCD的更高层封装
B. 它们不支持任务间的依赖关系
C. 它们无法取消已提交的任务
D. 它们只能在主线程上运行
答案:A
23. Swift中,如何解决类实例之间的循环强引用?
A. 使用weak关键字声明弱引用
B. 使用unowned关键字声明无主引用
C. 将引用设置为nil
D. A和B
答案:D
24. 关于内存管理,ARC的作用是:
A. 自动清理磁盘空间
B. 自动管理引用计数,在适当的时候释放对象内存
C. 自动修复内存泄漏
D. 自动处理循环引用
答案:B
25. 在Swift中,闭包(Closure)是:
A. 引用类型
B. 值类型
C. 既不是引用类型也不是值类型
答案:A
26. 如果一个闭包可能在函数返回后才被调用,应该用什么关键字标记?
A. @nonescaping
B. @escaping
C. @autoclosure
答案:B
27. 以下哪个不是iOS本地数据持久化的方案?
A. UserDefaults
B. Keychain
C. Core Data
D. NSCachedURLResponse
答案:D
28. HTTP和HTTPS的主要区别是:
A. HTTPS速度更快
B. HTTPS对传输内容进行了加密,更安全
C. HTTP是TCP协议,HTTPS是UDP协议
D. 没有区别
答案:B
29. 在Xcode中,用于检测内存泄漏和性能问题的工具是:
A. Debug Navigator
B. Instruments
C. Asset Catalog
D. Interface Builder
答案:B
30. 以下哪个是Swift包管理器?
A. CocoaPods
B. Carthage
C. Swift Package Manager (SPM)
D. Homebrew
答案:C
31. 处理App国际化(Internationalization & Localization)时,字符串应该放在:
A. 代码里直接写
B. 一个独立的Swift文件中
C. Localizable.strings文件里
D. Info.plist里
答案:C
32. 推送通知(Push Notification)的流程中,APNs指的是:
A. Apple Push Notification service
B. Apple Phone Number service
C. A Personal Notification server
答案:A
33. 在Swift中,@State 属性包装器的作用是:
A. 声明一个全局状态
B. 声明一个视图的局部、可变状态,当其改变时更新视图
C. 声明一个计算属性
D. 声明一个常量
答案:B
34. #available关键字用于:
A. 检查设备型号
B. 检查系统版本,实现API可用性检查
C. 检查网络是否可用
D. 检查磁盘空间
答案:B
35. lazy关键字修饰的属性:
A. 是线程安全的
B. 必须在声明时初始化
C. 是计算属性
D. 其初始值直到第一次被访问时才会被计算
答案:D
36. dynamic关键字的作用是:
A. 让Swift的属性或方法能够被Objective-C运行时动态分发
B. 让变量可以动态改变类型
C. 提高代码性能
D. 声明一个动态库
答案:A
37. 在KVO(键值观察)中,被观察的属性需要用哪个关键字修饰?
A. @objc dynamic
B. @observable
C. @KVO
D. @property
答案:A
38. Codable协议的作用是:
A. 数据加密解密
B. 将对象序列化和反序列化为JSON或其他格式
C. 编写可解码的代码
D. 网络编码
答案:B
39. @frozen枚举的作用是:
A. 表示枚举是冻住的,不能使用
B. 表示枚举的内存布局是稳定的,编译器可以进行优化
C. 表示枚举case是固定的,未来不会添加新的case
D. B和C
答案:D
40.Objective-C 中 isa 指针的作用是?
A. 指向对象的父类
B. 指向对象所属的类
C. 指向对象的属性
D. 指向对象的协议
答案:B
41.Instruments 工具中的 Time Profiler 用于?
A. 内存泄漏检测
B. CPU 性能分析
C. 网络请求分析
D. UI 层级查看
答案:B
42.内存泄漏主要由什么引起?
A. 网络错误
B. 循环引用
C. UI 渲染过慢
D. 磁盘不足
答案:B
43.iOS 中单元测试框架是?
A. XCTest
B. JUnit
C. Mocha
D. Jasmine
答案:A
44.UITableViewCell 重用机制的核心是?
A. 缓存图片
B. 通过 reuseIdentifier 复用 Cell
C. 每次都新建 Cell
D. ARC 自动优化
答案:B
45.AutoLayout 约束冲突时,系统会?
A. 崩溃
B. 自动移除部分约束
C. 忽略所有约束
D. 进入调试模式
答案:B
46.iOS 响应链传递顺序是?
A. UIApplication → UIWindow → UIView
B. UIApplication → UIWindow → UIViewController
C. UIView → UIWindow → UIApplication
D. UIView → UIViewController → UIWindow → UIApplication
答案:D
47.GCD 中 dispatch_async 的特点是?
A. 同步执行
B. 异步执行,不阻塞当前线程
C. 必须在主线程执行
D. 会阻塞队列
答案:B
48.KVO 的实现依赖于?
A. Method Swizzling
B. isa-swizzling(动态生成子类)
C. Runtime hook
D. 手动通知
答案:B
49.iOS 中自动释放池 @autoreleasepool 的作用是?
A. 延长对象生命周期
B. 提前释放对象
C. 统一管理延迟释放对象
D. 防止循环引用
答案:C
50.unowned 和 weak 的区别是?
A. weak 必须是 Optional可选型,unowned 可以是非 Optional 可选型
B. weak 不会释放对象,unowned 会释放
C. weak 更安全,unowned 不安全
D. 两者完全相同
答案:A
51.Objective-C 中 id 类型表示?
A. 任意对象指针类型
B. 任意整数类型
C. 任意字符串类型
D. 任意函数类型
答案:A
二、判断题****
- Objective-C的@property默认是nonatomic。
答案:正确
解析:@property默认是nonatomic,线程不安全但性能更高。
- GCD的DispatchQueue.main是串行队列。
答案:正确
解析:主队列是串行队列,确保UI操作按顺序执行。
- Objective-C的__weak引用不会增加对象的引用计数。
答案:正确
解析:__weak引用不增加引用计数,避免循环强引用。
- Objective-C的__weak引用在对象释放后会自动置为nil。
答案:正确
解析:__weak引用在对象释放后自动置为nil,避免野指针。
5. 在Swift中,协议(Protocol)只能定义方法,不能定义属性。
答案:错误
6. Swift的类不支持多继承,但可以通过协议实现类似的功能。
答案:正确
7. Swift中的泛型只能用于函数,不能用于类型(如类、结构体)。
答案:错误
8. iOS的响应者链(Responder Chain)从最顶层的UIWindow开始。
答案:错误
9. Auto Layout的约束冲突会导致运行时崩溃。
答案:错误
10. 离屏渲染(Offscreen Rendering)一定会导致性能问题,应该完全避免。
答案:错误
11. GCD的全局并发队列(Global Concurrent Queue)默认是串行的。
答案:错误
12. 循环引用(Retain Cycle)只会发生在两个对象之间。
答案:错误
13. UserDefaults适合存储大量数据,如图片、视频等。
答案:错误
14. Core Data是一个关系型数据库,与SQLite没有区别。
答案:错误
15. Swift中,访问控制级别private表示只能在当前类中访问。
答案:正确
16. map、filter、reduce是Swift中的高阶函数。
答案:正确
17. try?会将错误转换为可选值,如果发生错误,返回nil。
答案:正确
18. 类型别名(Type Alias)不会创建新类型,只是为现有类型提供一个别名。
答案:正确
19. 运算符重载(Operator Overloading)可以改变现有运算符的优先级和结合性。
答案:错误
20. 扩展(Extension)可以为现有类型添加新的存储属性。
答案:错误
21. 动态派发(Dynamic Dispatch)的效率总是低于静态派发(Static Dispatch)。
答案:正确
22. Keychain是iOS中用于安全存储敏感数据的地方。
答案:正确
23. Method Swizzling是一种安全且推荐使用的技术,可以随意使用。
答案:错误
24. 通用链接(Universal Links)使用标准的HTTP/HTTPS链接来打开App。
答案:正确
25. 实现App内购买(In-App Purchase)必须使用StoreKit框架。
答案:正确
26. Combine框架是Apple提供的响应式编程框架。
答案:正确
27. Actor是Swift中用于并发编程的类型,可以防止数据竞争。
答案:正确
28.SwiftUI 中的 body 属性是存储属性。
答案:错误 它是计算属性
29.Objective-C 中每个对象都有一个 isa 指针。
答案:正确
30.RunLoop 只能在主线程使用,子线程不能使用。
答案:错误
31.Objective-C 中 nil 给对象发送消息不会崩溃。
答案:正确
32.unowned 引用对象释放后访问会崩溃。
答案:正确
33.SwiftUI 界面更新是声明式的,不需要手动刷新。
答案:正确
34.信号量(Semaphore)可以控制并发数量。
答案:正确
35.GCD 的主队列是串行队列。
答案:正确
36.final class可以防止被继承
答案:正确
37.protocol中定义的属性默认是{ get set }可读写。
答案:错误(需显式声明,默认只读)
38.@autoreleasepool可手动释放临时对象。
答案:正确
39.Bitcode是编译后的中间代码,可优化大小。
答案:正确
40.在iOS中,可通过NSNotificationCenter实现跨类通信。
答案:正确
41.guard let解包失败时程序会崩溃
答案:错误
42.Swift中==和===的区别是前者比较值,后者比较引用地址
答案:正确
43.@autoclosure属性可以将表达式自动转换为闭包
答案:正确
44.Swift的Protocol可以定义静态方法
答案:正确
45.Objective-C中id类型可以指向任何对象,无需类型转换
答案:正确
44.inout 参数的行为类似于C语言中的传递指针,它直接将内存地址传递给函数。
答案:错误
解析:inout 参数传递的是“值进入,值传出”,并非直接传递地址。它可以像引用一样修改外部变量,但其实现机制(拷贝-in拷贝-out)与传递指针有区别。
45.Swift 的 optional 类型本质是一个枚举(Enum),包含 some 和 none 两个 case。
答案:正确
解析:Optional 的定义是 enum Optional { case none; case some(Wrapped) }。
46.String 和 Array 在 Swift 中都是值类型
答案:正确
解析:String, Array, Dictionary, Set 都是值类型。
47.some 关键字(不透明类型)主要用于返回遵循某个协议的具体类型,但隐藏具体类型信息。
答案:正确
48.Swift 的 actor 类型通过串行执行其成员方法来确保数据隔离和线程安全。
答案:正确
解析:这是 Swift 并发中 actor 的主要特性,它通过隔离数据来防止数据竞争。
49.在 Swift 中,循环引用(Retain Cycle)只会发生在类实例之间,值类型之间不会发生。
答案:正确
解析:值类型在赋值时是拷贝,没有引用关系,因此不会产生循环引用。
50.自动引用计数(ARC)只管理引用类型(Class)的内存,不管理值类型(Struct, Enum)的内存。
答案:正确
解析:ARC 的“引用计数”只适用于引用类型。值类型由系统管理其内存,通常在栈上分配和销毁。
51.使用 lazy 关键字修饰的属性,其初始化过程是线程安全的。
答案:错误
解析:lazy 属性的初始化器在首次访问时调用,Swift 不保证这个过程是线程安全的。如果需要,应自行添加同步机制。
52.ViewController 的 viewDidLoad 方法在其视图被添加到窗口后调用。
答案:错误
解析:viewDidLoad 在视图控制器加载其视图层次结构到内存后调用,此时视图还未添加到窗口。添加到窗口后调用的是 viewDidAppear。
53.frame 和 bounds 都是 CGRect 类型,frame 是相对于父视图坐标系的,而 bounds 是相对于自身坐标系的。
答案:正确
54.使用 UIImage(named:) 方法加载图片会缓存图片数据,而 UIImage(contentsOfFile:) 不会。
答案:正确
解析:UIImage(named:) 会使用系统缓存,适合频繁使用的资源。UIImage(contentsOfFile:) 直接从路径读取,无缓存,适合大图或一次性图片。
55.deinit 方法在 ARC 将对象内存释放后调用。
答案:错误
解析:deinit 在 ARC准备释放对象内存之前调用,此时实例还未被释放。
56.didSet 属性观察器在初始化方法(init)中设置属性值时不会被调用。
答案:正确
解析:属性观察器 didSet 和 willSet 在初始化方法中设置属性值时不会被调用。
57.响应链(Responder Chain)是 Cocoa Touch 中处理事件的一种机制,事件从初始对象向上传递到 UIApplication。
答案:正确
解析:响应链从第一响应者开始,依次向上传递(如 view -> viewController -> window -> application),直到有对象处理该事件。
58.在 Swift 和 Objective-C 混编项目中,Swift 类要暴露给 Objective-C 代码,需要继承自 NSObject 或用 @objc 修饰。
答案:正确
59.lazy var 存储属性不能拥有 didSet 属性观察器。
答案:错误
解析:可以拥有。lazy var 是存储属性,完全支持属性观察器。
三、简答题****
1. 简述Swift中协议(Protocol)和类的区别。
答: 区别是协议只声明接口,不提供实现;类可以提供具体实现。
2. 什么是响应者链(Responder Chain)?它是如何工作的?
答:响应者链是由响应者对象组成的层次结构。事件首先发送给初始响应者,如果它不处理,就传递给下一个响应者,直到UIApplication对象。
3. 简述UITableViewCell的重用机制原理和目的。
答: 原理是通过重用标识符从重用池中获取可复用的Cell。目的是避免频繁创建和销毁Cell,提升性能并降低内存占用。
4. Objective-C 中 Category 和 Extension 的区别?
答:Category 可以给类添加方法但不能添加实例变量;Extension 常用于类的私有扩展,可添加属性和方法。
5.什么是动态派发(Dynamic Dispatch)和静态派发(Static Dispatch)?
答: 静态派发在编译时确定要调用的方法地址,效率高。动态派发在运行时根据对象的实际类型来确定要调用的方法地址,支持多态,效率稍低。
6.Objective-C 中 id 和 instancetype 的区别?
答:id 表示任意对象,编译期不检查类型;instancetype 表示返回当前类或其子类实例,编译期更安全。
7.iOS 中常见的循环引用场景有哪些?
答:闭包(closure)捕获 self、delegate 强引用、Timer/Notification 使用不当等。
8.autoreleasepool 的作用是什么?
答:在合适的时机延迟释放对象,降低内存峰值,用于循环创建临时对象时释放内存。
9.KVC 的实现原理?
答:通过字符串 key 动态查找 setter/getter 方法,若无则访问实例变量。
10.KVO 的实现原理?
答:Runtime 动态生成子类,重写 setter 方法,在修改属性时通知观察者。
11.Objective-C 消息发送机制是什么?
答:调用方法时会转为 objc_msgSend,通过 isa 找类的方法缓存、方法列表,若找不到进入消息转发流程。
12.RunLoop 的作用?
答:保持线程存活,处理事件(触摸、定时器、网络),节省资源。
13.RunLoop 的常见应用场景?
答:保持子线程常驻、延迟执行任务、监控卡顿、图片懒加载等。
14.UIView 和 CALayer 的关系?
答:UIView 负责事件处理和响应,CALayer 负责绘制和渲染,UIView 内部有一个根 Layer。
15.frame 和 bounds 的区别?
答:frame 是相对父视图的坐标系,bounds 是相对自身的坐标系。
16.如何减少 TableView 的卡顿?
答:预估高度、异步加载图片、复用 cell、减少层级。
17.卡顿监控的常见实现原理?
答:通过 RunLoop 监听主线程是否长时间卡在某个状态。
-
iOS 沙盒机制的作用?
答:隔离应用数据,防止互相访问,提高安全性。 -
Swift 的 Optional 有什么作用?
答:表示变量可能有值也可能为 nil,避免野指针,提高类型安全性。
20.ARC 的工作原理是什么?
答:编译器自动插入 retain/release 代码管理引用计数,当引用计数为 0 时对象被释放。
21.如何解决闭包中的循环引用?
答:使用 [weak self] 或 [unowned self] 捕获 self。
22.结构体的方法若需修改属性,需要怎么做?
答:方法需标记为 mutating
23.解释「同步」(Sync)和「异步」(Async)任务派发的区别。
答:async:异步派发。将任务添加到队列后,函数立即返回,不等待任务执行完成。不会阻塞当前线程。
sync:同步派发。将任务添加到队列后,函数会等待任务执行完成后再返回。会阻塞当前线程,直到任务完成。需谨慎使用,以免引起死锁。
24.对比 GCD 和 OperationQueue,它们各自的优势和适用场景是什么?
答:
GCD:更轻量级,C API,执行简单任务(派发到全局队列或主队列)代码简洁。
OperationQueue:基于 GCD 构建的面向对象抽象。提供更丰富的功能:
依赖关系(Dependencies):可以设置操作之间的执行顺序。
取消操作(Cancellation):可以取消单个或所有排队或正在执行的操作。
状态查询(KVO):可以监听操作的状态(isReady, isExecuting, isFinished, isCancelled)。
最大并发数(maxConcurrentOperationCount):可以方便地控制并发数量(实现串行队列效果)。
25.draw(_ rect: CGRect) 和 setNeedsDisplay() 方法的作用和调用时机是什么?
答:draw(_ rect: CGRect):是 UIView 的方法,用于自定义视图的绘制内容(使用 Core Graphics)。系统会自动调用它。
setNeedsDisplay():标记视图的某部分需要重绘。调用后,系统会在下一个绘制周期调用 draw(_:) 方法。
26. 「通知」(Notification)和「委托」(Delegate)模式分别适用于什么场景?
答:委托(Delegate):适用于一对一的通信。关系紧密,通常有明确的层级或所属关系(如 UITableView 和它的 delegate)。
通知(Notification):适用于一对多的、松耦合的通信。发送者不需要知道谁接收,接收者也不需要知道发送者是谁(通过 NotificationCenter 广播)。
27.简述 RunLoop 与线程的关系。
答:每个线程(包括主线程)都有且只有一个对应的 RunLoop。主线程的 RunLoop 默认是开启的。子线程的 RunLoop 需要手动获取(RunLoop.current)和运行(run)。
28.解释 Swift 中「写时复制」(Copy-on-Write) 的实现原理及其对于值类型的意义。
答:「写时复制」是一种优化技术。当值类型(如 Array, String) 被赋值时,底层存储并不会立即复制,而是共享同一份内存。只有当其中一个副本被修改(写入)时,才会真正进行复制操作。这减少了不必要的内存拷贝,提升了性能。
29.什么是类型别名(Type Alias)?它的作用是什么? 答: 使用typealias关键字为现有类型定义另一个名字。作用是提高代码可读性;简化复杂的类型书写。
30.什么是内存访问冲突(Memory Access Conflict)?如何避免? 答: 当同一时间对同一内存地址进行多次访问,且至少有一个是写操作时发生。避免方法是理解inout参数的访问时机;避免在函数参数中传递同一变量的多个引用。
31.什么是深链接(Deep Linking)和通用链接(Universal Links)? 答: 深链接通过自定义URL Scheme直接打开App。通用链接使用标准的HTTP/HTTPS链接来打开App。
32.Swift并发中,Task和DispatchQueue的区别? 答: DispatchQueue是GCD的队列,用于安排闭包执行。Task是Swift并发模型中的单位,用于运行异步代码。
33.Core Data和SQLite的直接使用有何不同?
答: Core Data是一个对象图管理框架,可将对象持久化到多种存储中。直接使用SQLite是操作关系型数据库,需要编写SQL语句。
34.什么是「访问控制」(Access Control)?private, fileprivate, internal, public, open 的区别是什么?
答:访问控制用于限制代码模块中的代码级别。
private:仅在当前定义的作用域内可见。
fileprivate:在当前源文件内可见。
internal:默认级别,在整个模块(App 或 Framework)内可见。
public:可以被其他模块导入使用,但不能被继承或重写。
open:可以被其他模块导入使用,并且可以被继承或重写。
35. NSCache 和 Dictionary 在用于缓存时的主要区别是什么?
答:NSCache 是专为缓存设计的类,提供 Dictionary 没有的特性:
自动驱逐:在内存紧张时自动移除对象。
线程安全:可以在多线程环境中安全使用。
成本计算:可以为每个缓存对象指定一个「成本」,并设置总成本限制。
36.除了 weak 和 unowned,还有哪些方法可以打破循环引用?
答:
使用「闭包捕获列表」明确指定捕获关系([weak self])。
重新设计对象之间的关系,使用「委托模式」(weak delegate)。
使用「值类型」替代引用类型来打破循环。
在适当时机手动断开引用(如 deinit 中将强引用置为 nil)。
36. 解释「竞态条件」(Race Condition) 和「死锁」(Deadlock),并各举一个 iOS 开发中的例子。
答:
竞态条件:多个线程访问共享数据且未正确同步,导致结果依赖于执行顺序。例子:两个线程同时修改同一个数组。
死锁:两个或多个线程互相等待对方持有的资源,导致所有线程都无法继续执行。例子:在主线程上同步派发任务到主队列。
37. 在 SwiftUI 中,@State, @Binding, @ObservedObject, @StateObject 分别用于什么场景?
答:
@State:用于视图内部的私有状态,通常用于值类型。
@Binding:用于与父视图共享一个状态引用。
@ObservedObject:用于外部遵循 ObservableObject 的引用类型,通常由父视图传入。
@StateObject:用于视图内部创建和拥有的外部可观察对象,确保其生命周期与视图一致。
38. 解释 Swift 新并发框架中的 async/await 是如何工作的?
答:
async 标记一个函数是异步的。await 标记一个「挂起点」(Suspension Point)。当执行到 await 时,当前线程可能被释放去执行其他任务,而异步函数被挂起。当异步操作完成后,系统会在某个空闲线程上恢复该函数的执行。
39.actor 是什么?它是如何保证数据安全的?
答:
actor 是一种引用类型,用于在并发程序中安全地访问共享可变状态。
数据安全保证:actor 通过「数据隔离」来保证。其内部的状态(属性)只能通过其自身的方法来访问。编译器会自动确保这些方法(或 async 定义的属性)是互斥执行的(即同一时刻只有一个调用者能访问 actor 的内部状态),从而防止数据竞争。
40.draw(_ rect: CGRect) 和 setNeedsDisplay() 方法的作用和调用时机是什么?
答:
draw(_ rect: CGRect):是 UIView 的方法,用于自定义视图的绘制内容(使用 Core Graphics)。系统会自动调用它。
setNeedsDisplay():标记视图的某部分需要重绘。调用后,系统会在下一个绘制周期调用 draw(_:) 方法。