1.什么是 CoreData?它与 SQLite 和 Realm 有什么区别?
答案:
CoreData 是苹果官方提供的一个面向对象的持久化框架,它可以将应用程序的数据存储到 SQLite、二进制文件或内存中。与 SQLite 和 Realm 相比,CoreData 最大的优势在于它是一个面向对象的框架,可以直接操作对象,避免了使用 SQL 语句的繁琐和容易出错的过程。另外,CoreData 还提供了强大的数据关系管理和对象版本控制功能,使得数据的管理更加方便和高效。
与 SQLite 相比,CoreData 更加适合处理大型数据集合,它可以使用一些高级技术来优化数据的读写性能,同时也更容易实现数据的实时同步和增量更新。而 Realm 则更加适合处理较小的数据集合,它采用了基于内存映射的数据结构设计,可以在保证高性能的同时提供更好的安全性和稳定性。
2.请解释下面的代码块有什么问题,并提供一种修复方法。
let vc = MyViewController() vc.modalPresentationStyle = .fullScreen present(vc, animated: true, completion: nil)
答案:
上面的代码块的问题是可能会导致内存泄漏。因为 present(_:animated:completion:) 方法会将传入的 view controller 保留在内存中,而没有释放。这会导致 view controller 永远不会被销毁,造成内存泄漏。
为了修复这个问题,可以使用 weak 引用来避免循环引用,例如:
let vc = MyViewController() vc.modalPresentationStyle = .fullScreen present(vc, animated: true) { [weak self, weak vc] in guard let self = self, let vc = vc else { return } // do something after the presentation of vc is completed }
这里使用了 [weak self, weak vc] 弱引用来避免循环引用,然后在闭包中使用 guard 语句来确保 self 和 vc 弱引用没有被释放。
3.什么是 Swift 中的防止 retain cycle(保持循环引用)?
答案:在 Swift 中,防止循环引用的主要方法是使用捕获列表(capture list)和弱引用(weak reference)。捕获列表是一个将自身的弱引用传递给闭包以防止循环引用的方法。在闭包中使用弱引用的另一种方法是使用无主引用(unowned reference),如果确定在闭包引用结束之前不会被释放,可以使用无主引用。
例如:
class Person { var name: String lazy var printName: () -> () = { [weak self] in if let weakSelf = self { print("My name is \(weakSelf.name)") } } init(name: String) { self.name = name } } var person: Person? = Person(name: "John") person?.printName() // "My name is John" person = nil
在上面的例子中,Person 类定义了一个 printName 闭包,其中使用了一个捕获列表,将 self 声明为弱引用。由于 printName 是延迟初始化的,它只有在第一次访问时才会被创建。在闭包中,我们首先检查 weakSelf 是否不为 nil,然后再访问它的 name 属性。由于 self 已经被释放,它将被置为 nil。
4.在Swift中,什么是协议继承?如何使用?
答案:在Swift中,协议继承是一种协议之间的关系,其中一个协议可以从另一个协议中继承一些属性、方法或其他需求。继承一个协议的协议可以在该协议的基础上增加新的需求,或者对其进行修改。协议继承可以实现代码重用和减少重复定义。
在Swift中,使用protocol关键字来定义一个协议,使用冒号(:)来表示协议继承。例如,以下是一个使用协议继承的示例:
protocol Printable { func print() } protocol Debuggable: Printable { func debug() }
在这个例子中,Debuggable协议继承自Printable协议,并增加了debug()方法的需求。这意味着Debuggable协议不仅要实现print()方法,还要实现debug()方法。
可以将协议继承与类继承一起使用,例如:
class MyClass: Debuggable { func print() { print("Printing...") } func debug() { print("Debugging...") } }
在这个例子中,MyClass类继承了Debuggable协议,并实现了协议中的print()和debug()方法。
协议继承可以帮助程序员减少代码冗余并提高代码可读性。
5.请解释下以下的代码中 defer 的作用
func test() { defer { print("First defer") } defer { print("Second defer") } print("Test") }
答案:defer 语句用于在函数执行结束前执行一些必要的清理工作,无论是由于返回还是抛出错误而离开函数。在上述代码中,test 函数执行时先输出 Test,接着执行两个 defer 语句,最后结束函数。defer 语句的执行顺序是 FILO(后进先出)的,因此第二个 defer 语句先于第一个 defer 语句执行,输出 Second defer 和 First defer。