乐闻世界logo
搜索文章和话题

面试题手册

Swift 中的枚举是什么?如何使用关联值和原始值?

Swift 中的枚举是什么?如何使用关联值和原始值?枚举支持哪些高级特性?Swift 中的枚举是一种定义一组相关值的类型,比其他语言的枚举更强大。Swift 的枚举可以包含关联值、原始值,并且可以定义方法和计算属性。基本枚举定义:enum CompassPoint { case north case south case east case west}var direction = CompassPoint.northdirection = .south关联值:每个枚举成员可以存储不同类型的关联值类似于带有附加数据的枚举示例: enum Barcode { case upc(Int, Int, Int, Int) case qrCode(String) } var productBarcode = Barcode.upc(8, 85909, 51226, 3) productBarcode = .qrCode("ABCDEFGHIJKLMNOP") switch productBarcode { case .upc(let numberSystem, let manufacturer, let product, let check): print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)") case .qrCode(let productCode): print("QR code: \(productCode)") }原始值:枚举成员可以有相同类型的预填充值使用 rawValue 访问原始值必须是字符串、字符、整数或浮点数示例: enum Planet: Int { case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune } let earth = Planet(rawValue: 3) print(earth?.rawValue) // Optional(3)枚举方法:enum TrafficLight { case red, yellow, green func description() -> String { switch self { case .red: return "Stop" case .yellow: return "Caution" case .green: return "Go" } } mutating func next() { switch self { case .red: self = .green case .yellow: self = .red case .green: self = .yellow } }}计算属性:enum Rectangle { case width(height: Double) case height(width: Double) var area: Double { switch self { case .width(let height): return height * 10 case .height(let width): return width * 5 } }}递归枚举:使用 indirect 关键字标记允许枚举成员引用枚举本身示例: enum ArithmeticExpression { case number(Int) indirect case addition(ArithmeticExpression, ArithmeticExpression) indirect case multiplication(ArithmeticExpression, ArithmeticExpression) } let five = ArithmeticExpression.number(5) let four = ArithmeticExpression.number(4) let sum = ArithmeticExpression.addition(five, four) let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))CaseIterable 协议:enum CompassPoint: CaseIterable { case north, south, east, west}let numberOfCases = CompassPoint.allCases.countfor direction in CompassPoint.allCases { print(direction)}Comparable 协议:enum Priority: Int, Comparable { case low = 1 case medium = 2 case high = 3 static func < (lhs: Priority, rhs: Priority) -> Bool { return lhs.rawValue < rhs.rawValue }}let priority1 = Priority.highlet priority2 = Priority.lowprint(priority1 > priority2) // true枚举的高级特性:支持泛型支持协议支持扩展支持初始化器支持下标最佳实践:使用枚举表示有限的、相关的值集合使用关联值传递额外的数据使用原始值表示固定的值为枚举添加方法提高可读性使用递归枚举处理树形结构
阅读 0·2月21日 15:10

Swift 中的扩展是什么?如何使用扩展?

Swift 中的扩展是什么?如何使用扩展?扩展可以添加哪些功能?Swift 中的扩展是一种为现有的类、结构体、枚举或协议类型添加新功能的机制。扩展可以添加新的功能,但不能重写现有的功能。扩展的基本用法:extension Int { var squared: Int { return self * self } func isEven() -> Bool { return self % 2 == 0 }}let number = 5print(number.squared) // 25print(number.isEven()) // false扩展可以添加的功能:计算属性: extension Double { var km: Double { return self * 1000 } var m: Double { return self } var cm: Double { return self / 100 } var mm: Double { return self / 1000 } } let oneInch = 25.4.mm print("One inch is \(oneInch) meters")实例方法: extension String { func reversed() -> String { return String(self.reversed()) } func trimmed() -> String { return self.trimmingCharacters(in: .whitespacesAndNewlines) } } let text = "Hello World" print(text.reversed()) // dlroW olleH类型方法: extension Int { static func random(in range: Range<Int>) -> Int { return Int.random(in: range) } } let randomNum = Int.random(in: 1..<100)初始化器: extension UIColor { convenience init(hex: String) { let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int: UInt64 = 0 Scanner(string: hex).scanHexInt64(&int) let a, r, g, b: UInt64 } }下标: extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } } let array = [1, 2, 3] print(array[safe: 1]) // Optional(2) print(array[safe: 10]) // nil嵌套类型: extension Int { enum Kind { case negative, zero, positive } var kind: Kind { switch self { case 0: return .zero case let x where x > 0: return .positive default: return .negative } } }协议扩展:protocol TextRepresentable { var textualDescription: String { get }}extension TextRepresentable { func describe() -> String { return "Description: \(textualDescription)" }}struct Person: TextRepresentable { var textualDescription: String}let person = Person(textualDescription: "John Doe")print(person.describe())条件扩展:extension Collection where Element: Equatable { func allEqual() -> Bool { guard let first = first else { return true } return all { $0 == first } }}extension Array where Element: Numeric { func sum() -> Element { return reduce(0, +) }}扩展的限制:不能添加存储属性不能添加属性观察器不能重写现有的方法不能添加指定的初始化器不能添加反初始化器最佳实践:使用扩展组织相关功能使用协议扩展提供默认实现使用条件扩展为特定类型添加功能避免在扩展中添加过多功能保持扩展的单一职责原则
阅读 0·2月21日 15:10

Swift 中的泛型是什么?如何使用泛型?

Swift 中的泛型是什么?如何使用泛型?什么是泛型约束和关联类型?Swift 中的泛型是一种强大的特性,允许你编写灵活、可重用的代码,同时保持类型安全。泛型使你能够编写适用于多种类型的函数和类型,而不需要为每种类型重复编写代码。泛型的基本概念:泛型允许你使用占位符类型名称(如 T)来表示类型编译器会在使用时推断具体的类型提供类型安全,避免运行时类型错误减少代码重复,提高代码复用性泛型函数:// 泛型函数示例func swapValues<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp}// 使用泛型函数var x = 10var y = 20swapValues(&x, &y)泛型类型:// 泛型结构体struct Stack<Element> { private var items: [Element] = [] mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element? { return items.popLast() }}// 使用泛型类型var intStack = Stack<Int>()intStack.push(1)泛型约束:限制泛型类型必须遵循特定协议使用 where 子句添加更复杂的约束常见约束类型:T: Equatable - 类型必须遵循 Equatable 协议T: Comparable - 类型必须遵循 Comparable 协议T: SomeProtocol - 类型必须遵循指定协议T: AnyObject - 类型必须是类类型// 泛型约束示例func findFirstIndex<T: Equatable>(of value: T, in array: [T]) -> Int? { for (index, item) in array.enumerated() { if item == value { return index } } return nil}// 使用 where 子句func allItemsMatch<C1: Container, C2: Container>(_ container1: C1, _ container2: C2) -> Bool where C1.Item == C2.Item, C1.Item: Equatable { return true}关联类型:在协议中定义的占位符类型名称使用 associatedtype 关键字声明允许协议定义灵活的类型要求在遵循协议时指定具体类型// 带有关联类型的协议protocol Container { associatedtype Item mutating func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get }}// 遵循协议并指定关联类型struct IntStack: Container { typealias Item = Int private var items: [Int] = [] mutating func append(_ item: Int) { items.append(item) } var count: Int { return items.count } subscript(i: Int) -> Int { return items[i] }}最佳实践:合理使用泛型提高代码复用性使用泛型约束确保类型安全在协议中使用关联类型提高灵活性避免过度使用泛型导致代码复杂为泛型参数使用有意义的名称
阅读 0·2月21日 15:09

Swift 中的 guard 语句是什么?如何使用 guard 语句?

Swift 中的 guard 语句是什么?如何使用 guard 语句?guard 语句有什么优势?Swift 中的 guard 语句用于提前退出当前作用域,当条件不满足时执行 else 块中的代码。guard 语句使代码更加清晰,减少了嵌套层级。guard 语句的基本语法:func processAge(_ age: Int?) { guard let age = age else { print("Age is nil") return } guard age >= 18 else { print("Age must be 18 or older") return } print("Age is valid: \(age)")}guard 语句的特点:必须包含 else 块else 块中必须使用 return、break、continue 或 throw 等控制转移语句guard 条件为真时,继续执行后面的代码guard 条件为假时,执行 else 块可以使用可选绑定guard 语句的使用场景:可选绑定: func greet(name: String?) { guard let name = name else { print("Name is nil") return } print("Hello, \(name)") }条件检查: func divide(_ a: Int, by b: Int) throws -> Int { guard b != 0 else { throw DivisionError.divisionByZero } return a / b }多个条件检查: func registerUser(name: String?, age: Int?, email: String?) { guard let name = name, !name.isEmpty else { print("Invalid name") return } guard let age = age, age >= 18 else { print("Invalid age") return } guard let email = email, email.contains("@") else { print("Invalid email") return } print("User registered: \(name), \(age), \(email)") }类型转换: func processValue(_ value: Any) { guard let intValue = value as? Int else { print("Value is not an Int") return } print("Processing integer: \(intValue)") }guard 语句的优势:减少嵌套层级: // 不使用 guard func processWithoutGuard(_ value: Int?) { if let value = value { if value > 0 { if value < 100 { print("Valid value: \(value)") } else { print("Value too large") } } else { print("Value too small") } } else { print("Value is nil") } } // 使用 guard func processWithGuard(_ value: Int?) { guard let value = value else { print("Value is nil") return } guard value > 0 else { print("Value too small") return } guard value < 100 else { print("Value too large") return } print("Valid value: \(value)") }提高代码可读性:将错误处理放在前面主要逻辑在后面,更清晰减少缩进层级提前退出:在条件不满足时立即退出避免执行不必要的代码提高代码效率强制解包:guard let 确保后续代码可以使用解包后的值不需要重复检查可选值guard 语句在循环中的使用:func findFirstValidNumber(in numbers: [Int?]) -> Int? { for number in numbers { guard let validNumber = number else { continue } return validNumber } return nil}guard 语句与 if 语句的比较:guard:条件不满足时退出,满足时继续if:条件满足时执行,不满足时跳过guard 更适合提前退出场景if 更适合条件分支场景最佳实践:使用 guard 处理前置条件使用 guard 减少嵌套层级在 guard else 块中提供清晰的错误信息避免在 guard 中执行复杂逻辑合理使用 guard 提高代码可读性
阅读 0·2月21日 15:09

Swift 中的初始化器是什么?什么是指定初始化器、便利初始化器和可失败初始化器?

Swift 中的初始化器是什么?什么是指定初始化器、便利初始化器和可失败初始化器?Swift 中的初始化器用于创建类、结构体或枚举的新实例。初始化器确保所有存储属性在使用前都有合适的初始值,并执行其他必要的设置。初始化器的基本概念:使用 init 关键字定义不需要 func 关键字可以有参数可以重载确保实例完全初始化后才能使用指定初始化器:类的主要初始化器完全初始化所有引入的属性调用父类的指定初始化器每个类至少有一个指定初始化器示例: class Vehicle { var numberOfWheels: Int var maxSpeed: Int init(numberOfWheels: Int, maxSpeed: Int) { self.numberOfWheels = numberOfWheels self.maxSpeed = maxSpeed } }便利初始化器:辅助初始化器,提供便捷的初始化方式必须调用同一个类中的其他初始化器最终必须调用指定初始化器使用 convenience 关键字标记示例: class Car: Vehicle { var brand: String init(brand: String, numberOfWheels: Int, maxSpeed: Int) { self.brand = brand super.init(numberOfWheels: numberOfWheels, maxSpeed: maxSpeed) } convenience init(brand: String) { self.init(brand: brand, numberOfWheels: 4, maxSpeed: 200) } convenience init() { self.init(brand: "Unknown") } }可失败初始化器:可能返回 nil 的初始化器使用 init? 或 init! 定义在初始化失败时返回 nil示例: struct Temperature { let celsius: Double init?(celsius: Double) { if celsius < -273.15 { return nil } self.celsius = celsius } init?(fahrenheit: Double) { let celsius = (fahrenheit - 32) * 5 / 9 if celsius < -273.15 { return nil } self.celsius = celsius } } let validTemp = Temperature(celsius: 25) let invalidTemp = Temperature(celsius: -300)初始化器规则:指定初始化器必须调用父类的指定初始化器便利初始化器必须调用同一个类中的其他初始化器在初始化完成前不能访问实例方法或属性必须先初始化当前类的属性,再调用父类初始化器两段式初始化:class Base { var value: Int init(value: Int) { // 第一阶段:初始化当前类属性 self.value = value // 第二阶段:调用父类初始化器 // 对于基类,没有父类 }}class Derived: Base { var extra: Int init(value: Int, extra: Int) { // 第一阶段:初始化当前类属性 self.extra = extra // 第二阶段:调用父类初始化器 super.init(value: value) // 现在可以访问实例方法 }}必需初始化器:使用 required 关键字标记所有子类必须实现该初始化器示例: class SomeClass { required init() { // 初始化代码 } } class SubClass: SomeClass { required init() { // 必须实现 } }最佳实践:合理使用指定初始化器和便利初始化器使用可失败初始化器处理无效输入遵循两段式初始化规则避免在初始化器中调用实例方法使用必需初始化器确保子类一致性
阅读 0·2月21日 15:07

Swift 中的 inout 参数是什么?如何使用 inout 参数?

Swift 中的 inout 参数是什么?如何使用 inout 参数?inout 参数有什么限制?Swift 中的 inout 参数允许函数直接修改传递给它的变量的值。默认情况下,Swift 的参数是常量,函数内部不能修改。使用 inout 关键字可以改变这一行为。inout 参数的基本用法:func swapValues(_ a: inout Int, _ b: inout Int) { let temp = a a = b b = temp}var x = 10var y = 20swapValues(&x, &y)print("x: \(x), y: \(y)") // x: 20, y: 10inout 参数的工作原理:函数调用时,将变量的值复制到参数中函数内部修改参数的值函数返回时,将修改后的值复制回原变量类似于引用传递,但实际是值复制使用场景:交换值: func swap<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp }修改多个值: func incrementAndDecrement(_ a: inout Int, _ b: inout Int) { a += 1 b -= 1 }累积计算: func accumulate(_ value: Int, into total: inout Int) { total += value } var sum = 0 accumulate(5, into: &sum) accumulate(10, into: &sum)inout 参数的限制:不能使用字面量或常量: func modify(_ value: inout Int) { value += 1 } // 错误:不能使用字面量 // modify(&10) // 错误:不能使用常量 // let x = 5 // modify(&x) // 正确:必须使用变量 var x = 5 modify(&x)不能传递计算属性: struct Point { var x: Int var y: Int var sum: Int { return x + y } } var point = Point(x: 3, y: 4) // 错误:不能传递计算属性 // modify(&point.sum)不能传递属性观察器: var counter: Int = 0 { didSet { print("Counter changed to \(counter)") } } // 错误:不能传递有属性观察器的属性 // modify(&counter)同一变量不能多次传递: func doubleBoth(_ a: inout Int, _ b: inout Int) { a *= 2 b *= 2 } var x = 5 // 错误:同一变量不能多次传递 // doubleBoth(&x, &x)不能在闭包中捕获 inout 参数: func process(_ value: inout Int) { // 错误:不能在闭包中捕获 inout 参数 // let closure = { value += 1 } }inout 参数与引用类型的区别:inout 参数:值类型,通过复制实现引用类型:直接传递引用示例: class ReferenceType { var value: Int init(value: Int) { self.value = value } } func modifyReference(_ obj: ReferenceType) { obj.value += 1 } func modifyValue(_ value: inout Int) { value += 1 }最佳实践:只在需要修改多个值时使用 inout 参数使用有意义的参数名提高可读性避免过度使用 inout 参数注意 inout 参数的性能影响考虑使用返回值替代 inout 参数
阅读 0·2月21日 15:07

Swift 中的 lazy 属性是什么?如何使用 lazy 属性?

Swift 中的 lazy 属性是什么?如何使用 lazy 属性?lazy 属性的初始化时机是什么?Swift 中的 lazy 属性是一种延迟初始化机制,只有在第一次访问时才会计算其初始值。这对于初始化成本较高或依赖其他属性的场景非常有用。lazy 属性的特点:使用 lazy 关键字声明必须是变量(var),不能是常量(let)必须有初始值或闭包初始化第一次访问时才进行初始化初始化后保持值不变(除非被重新赋值)线程不安全,多线程环境下需要注意基本用法:class DataImporter { var filename = "data.txt"}class DataManager { lazy var importer = DataImporter() var data = [String]()}let manager = DataManager()manager.data.append("Some data")// 此时 importer 还没有被初始化print(manager.importer.filename)// 第一次访问 importer 时才进行初始化使用闭包初始化:class ImageLoader { lazy var image: UIImage = { let url = URL(string: "https://example.com/image.jpg")! let data = try! Data(contentsOf: url) return UIImage(data: data)! }() lazy var cachedImage: UIImage = { print("Loading image...") return UIImage(named: "cached")! }()}lazy 属性的初始化时机:第一次访问属性时不是在类实例化时即使访问失败,也会尝试初始化示例: class LazyExample { lazy var expensiveValue: Int = { print("Calculating expensive value...") return Int.random(in: 1...1000) }() } let example = LazyExample() print("Instance created") // 输出: Instance created print(example.expensiveValue) // 输出: Calculating expensive value... // 输出: (随机数) print(example.expensiveValue) // 输出: (相同的随机数,不会重新计算)lazy 属性的应用场景:初始化成本高的对象: class DatabaseManager { lazy var connection: DatabaseConnection = { let conn = DatabaseConnection() conn.connect() return conn }() }依赖其他属性的对象: class ViewController { var userID: String? lazy var userProfile: UserProfile = { guard let id = userID else { return UserProfile.guest } return UserProfile.load(id: id) }() }单例模式: class Singleton { static let shared = Singleton() lazy var expensiveResource: Resource = { return Resource() }() }注意事项:lazy 属性不是线程安全的不能在结构体中使用 lazy 属性(因为结构体是值类型)lazy 属性不能是常量如果初始化闭包抛出错误,需要处理错误在多线程环境下,可能需要添加同步机制最佳实践:用于初始化成本高的属性用于依赖其他属性的属性用于可能不会被使用的属性注意线程安全问题避免在 lazy 属性中使用 self 产生循环引用
阅读 0·2月21日 15:07

Swift 中的可选类型是什么?如何正确使用可选类型?

Swift 中的可选类型是什么?如何正确使用可选类型?什么是可选绑定、强制解包和隐式解包可选类型?Swift 中的可选类型是一种处理值可能缺失的安全机制,它表示一个变量要么有值,要么为 nil。可选类型定义:使用 ? 声明可选类型,如 var name: String?可选类型实际上是一个枚举:enum Optional<Wrapped> { case none; case some(Wrapped) }nil 表示没有值,只能用于可选类型可选绑定:使用 if let 或 guard let 安全地解包可选值if let:在条件作用域内使用解包后的值guard let:在函数或方法中提前退出,解包后的值在后续代码中可用示例: if let unwrappedName = optionalName { print(unwrappedName) } func processName(_ name: String?) { guard let unwrappedName = name else { return } print(unwrappedName) }强制解包:使用 ! 强制解包可选值如果可选值为 nil,会触发运行时错误只在确定可选值不为 nil 时使用示例:let name = optionalName!隐式解包可选类型:使用 ! 声明,如 var name: String!声明后可以像非可选类型一样使用但本质仍是可选类型,为 nil 时会崩溃主要用于初始化后不会为 nil 的情况,如 IBOutlet最佳实践:优先使用可选绑定而非强制解包使用 ?? 运算符提供默认值使用可选链 ?. 安全调用方法和属性避免过度使用隐式解包可选类型使用 guard let 提前处理 nil 情况
阅读 0·2月21日 15:07

Swift 中的属性观察器是什么?如何使用 willSet 和 didSet?

Swift 中的属性观察器是什么?如何使用 willSet 和 didSet?Swift 中的属性观察器用于监控和响应属性值的变化。当属性值被设置时,属性观察器会被触发,允许你在值改变前后执行自定义代码。属性观察器的类型:willSet:在新值存储之前调用可以访问新值(通过默认参数名 newValue)可以在设置新值之前执行验证或准备工作示例: swift class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps) { print("About to set totalSteps to \(newTotalSteps)") } } }didSet:在新值存储之后调用可以访问旧值(通过默认参数名 oldValue)可以在值改变后执行更新或通知操作示例: swift class StepCounter { var totalSteps: Int = 0 { didSet { print("Added \(totalSteps - oldValue) steps") } } }完整示例:class TemperatureMonitor { var temperature: Double { willSet { print("Temperature will change from \(temperature) to \(newValue)") if newValue > 100 { print("Warning: High temperature!") } } didSet { print("Temperature changed from \(oldValue) to \(temperature)") if temperature != oldValue { notifyTemperatureChange() } } } func notifyTemperatureChange() { print("Notifying temperature change...") }}let monitor = TemperatureMonitor()monitor.temperature = 25monitor.temperature = 105属性观察器的使用场景:数据验证: class Person { var age: Int { didSet { if age < 0 { age = 0 } if age > 150 { age = 150 } } } }UI 更新: class ViewModel { var isLoading: Bool = false { didSet { updateLoadingIndicator() } } func updateLoadingIndicator() { // 更新 UI 指示器 } }缓存失效: class DataCache { var data: [String: Any] = [:] { didSet { invalidateCache() } } func invalidateCache() { // 清除缓存 } }日志记录: class Logger { var logLevel: LogLevel = .info { didSet { print("Log level changed from \(oldValue) to \(logLevel)") } } }注意事项:属性观察器不能用于延迟属性(lazy)属性观察器不能用于常量属性(let)在初始化器中设置属性值不会触发属性观察器在 willSet 中修改属性值不会再次触发 willSet在 didSet 中修改属性值会再次触发属性观察器如果属性有默认值,初始化时不会触发属性观察器最佳实践:使用 willSet 进行值验证和准备使用 didSet 执行副作用和更新避免在属性观察器中执行耗时操作注意避免无限循环(在 didSet 中修改属性)使用有意义的参数名提高代码可读性
阅读 0·2月21日 15:07

Swift 中的属性包装器是什么?如何使用 @propertyWrapper?

Swift 中的属性包装器是什么?如何使用 @propertyWrapper?Swift 中的属性包装器是一种在属性设置和获取时添加额外逻辑的机制。属性包装器可以复用属性管理逻辑,减少代码重复。基本属性包装器:@propertyWrapperstruct TwelveOrLess { private var number: Int init() { self.number = 0 } var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } }}struct SmallRectangle { @TwelveOrLess var height: Int @TwelveOrLess var width: Int}var rectangle = SmallRectangle()rectangle.height = 10rectangle.width = 20print(rectangle.width) // 12带参数的属性包装器:@propertyWrapperstruct SmallNumber { private var maximum: Int private var number: Int init(wrappedValue: Int, maximum: Int) { self.maximum = maximum self.number = wrappedValue } var wrappedValue: Int { get { return number } set { number = min(newValue, maximum) } }}struct ZeroRectangle { @SmallNumber(wrappedValue: 0, maximum: 5) var height: Int @SmallNumber(wrappedValue: 0, maximum: 10) var width: Int}投射值:@propertyWrapperstruct SmallNumber { private var number: Int init(wrappedValue: Int) { self.number = wrappedValue } var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } var projectedValue: Bool { return number > 12 }}struct SomeStructure { @SmallNumber var someNumber: Int}var someStructure = SomeStructure()someStructure.someNumber = 4print(someStructure.$someNumber) // falsesomeStructure.someNumber = 14print(someStructure.$someNumber) // true常见的属性包装器用例:线程安全: @propertyWrapper struct ThreadSafe { private var value: T private let lock = NSLock() init(wrappedValue: T) { self.value = wrappedValue } var wrappedValue: T { get { lock.lock() defer { lock.unlock() } return value } set { lock.lock() defer { lock.unlock() } value = newValue } } }延迟加载: @propertyWrapper struct Lazy { private var value: T? var wrappedValue: T { mutating get { if let value = value { return value } let initialValue = wrappedValueFactory() value = initialValue return initialValue } } let wrappedValueFactory: () -> T init(wrappedValue: @autoclosure @escaping () -> T) { self.wrappedValueFactory = wrappedValue } }用户默认值: @propertyWrapper struct UserDefault { let key: String let defaultValue: T var wrappedValue: T { get { UserDefaults.standard.object(forKey: key) as? T ?? defaultValue } set { UserDefaults.standard.set(newValue, forKey: key) } } }属性包装器的最佳实践:使用属性包装器封装重复的属性逻辑使用投射值提供额外的功能为属性包装器提供合理的默认值注意属性包装器的性能影响在适当的地方使用属性包装器
阅读 0·2月21日 15:06