一、知识点

Property Wrapper,即特征包装器,其作用是将特征的 界说代码 与特征的存储办法代码 进行分别,抽取的办理的存储代码只需要编写一次,即可将功用应用于其它特征上。

1、根底用法

功用需求:确保值一app装置下载直小于或等于appear12

这儿我们直接运用 prapple tvopertapple watchy wrapper 进行封装演示

@propertyWrapper
struct Tapp storewelveOrLess {
private var number: Int
// wrappedValue变量的名字是固定的
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
init() {
self.swiftkeynumber = 0
}
}
struct SmallRectangle {
@TwelveOrLess var heighswift什么意思t: Int
@TwelveOrLswift代码是什么意思ess var width: Int
}
vappstorear rectangle = SmallRectangle()
print(rectangleapp store.height) // 0
rectanAPPgle.height = 10
print(rectangle.heiAppleght) // 10
rectangle.heighswift银行t = 24
print(rectangle.height) // 12

这儿可以注意到,在创立 SmallRectangle实例时,并不需要初始swift代码heightwidth

原因:
property wrapper 声明的特征,实践上在存储时的类型是 TwelveOrLess,只不过application编译器施了一些魔法,让它swifter对外露出的类型依然是被包swiftly装的本来的类型。
上面的 SmallRectangleappstore 结构体,等同于下方这种写法

struct SmallRectangle {appear
private var _height = TwelveOrLessApple()
private var _width = TwelveOrLess()
var heigappearht: Inapplicationt {
get { return _app id注册height.wrappedValue }
set { _height.wrappedValue = newValue }
}
var width: Int {
get { return _width.wrappedValue }
set { _width.wrappedValue = newValue }
}
}

2、设置初始值

@propertyswifterWrapper
struct SmallNumber {
private var maxiswift银行mum: Int
private var number: Int
var wrappeappreciatedValue: Int {
get { return number }
set { nuapple paymber = min(newValue, maximum) }
}
init() {
maximum = 12
number = 0
}
init(wrappedValue: Int) {
print("init(wrappedValue:)")
maximum = 1apple id2
number = min(wapple payrappedValue, maxiapple tvmum)
}
init(wrappedValue: Int, maximum: Int) {
priapproachnt("init(wrappedValue:maximumapp id注册:appearance)")
self.maximuswift什么意思m = maximum
number = min(wrappedValue, maximum)
}
}

运用了 @SmallNumber但没有指定初始化值

struct ZeroRectangle {
@SmallNumber var height: Int
@SmallNumber var width: Int
}
var zeroRectangle = ZeroRectangle()
print(zeroRectangle.height, zeroRectangle.width) // 0 0

运用了 @SmallNumber,并指定初始化值

这儿会调用 init(wrappedapple watchValue:) 办法

struct UnitRectangle {
@SmallNumber var height: Intapple id = 1
@SmallNumber var width: Int = 1
}
var unitRectangle = UnitRectangapp装置下载le()
print(unitRectangswift代码是什么意思le.heiappreciateght, unitRectangle.width) // 1 1

运用@SmallNumber,并传参apple tv进行初始化

这儿会调用 iniapple storet(wrappedValue:maximappearum:) 办法

struct NarrowRectangle {
// 报错:Extra argument 'wrappedValue' in call
// @SmallNumberapproach(wrappedValue: 2, maximum: 5) var height: Int = 1
// 这种初始化是可以的,调用 init(wrapplicationappedValue:maximum:) 办法
// @SswiftermallNumber(maximum: 9) vappearancear height: Int = 2
@SmallNumberswiftkey(wrappedValue: 2, maximum:swift怎么读 5) var height: Int
@SmallNumber(wrappedValue: 3, maximum: 4) var width: Int
}
vaapple tvr narrowRectangle = NarrowRectangle()
print(narrowRectangle.heigapple官网ht, narrowRectangle.width) // 2 3
narrowRectappearanceangle.hswift什么意思eight = 100
narrowRectangle.width = 100
print(narrowRectangle.height, narrowReAPPctangle.width) // 5 4

3、projectedValue

papp装置下载rojectedValueproperty wrapper 供给了额外的功用(如:标志某个情况,或Swift许记载 propeapple storerty wrapper 内部的改动等)

两者都是通过实例的特征名进行拜访,仅有不同的当地在于,projectedValue 需要在特征名前加上 $ 才可以拜访

  • wrappedVaswifterlue: 实例.特征名
  • projectedValue: 实例.$特征名

下面的代码将一个 projectedValue 特征添加到 SmallNumber 结构中,以在appearance存储该新值之前跟踪该特征包装器是否调整了该特征的新值。

@propertyWrapper
struct Smaswift代码是什么意思llNumber1 {
private var number: Int
var projectedValue: Bool
init() {
self.number = 0
self.projectedValue = false
}
var wrappedValue: Int {
getswift银行 { returswift世界结算体系n number }
set {
if newValue > 12 {
number = 12
projectedValue = true
} elapple idse {
number = newValue
projectedValue = false
}
}
}
}
struct SomeStructure {
@SmallNumber1 var someNumber: Int
}
var someswift银行Structure = SomeStructure()
someStructure.someNumber = 4
print(someStructswift代码ure.$someNumber) // false
soswift什么意思meStructure.sAppleomeNumapple watchber = 55
print(someStructure.$someNumber) // true

这儿的 someStructure.$someNumber拜访的是 projectedValue

4、运用约束

  • app装置下载能在协议里的特征运用
protocol SomeProtocol {
// Prswift代码operty 'sp' declared inside a protocol cannot have a wrapper
@SmallNumber1 var sp:app id注册 Bool { get seappreciatet }
}
  • 不能在 extensswifterion内运用
extension Soswift什么意思meStructure {
// Extensions must notswift代码是什么意思 contain storeswiftlyd properties
@SmallNumber1 var someProperty2: Int
}
  • 不能在 eswift代码num内运用
enum SomeEnum {
//appstore Property wrapper attribute 'SmallNumber1' can only be applied to a property
@Smaswift代码llNumber1 case a
case b
}
  • class里的 wrapper property不能掩盖其他的 property
class AClAppleass {
@SmallNumber1 var aPapple payroperty: Int
}
class BClass: ASwiftClaapp storess {
// Cannot override with a stored property 'aProperty'
oappearanceverride var aProperty: Int = 1
}
  • wrapper特征不能界说 gettersetteapple tvr办法
struct SomeStructure2 {
// Property wrapper cannot be applied to a computed property
@SmallNumber1 var someapp storeNumber: Int {
get {
reswifterturn 0
}
}
}
  • wrappeappearrappreciate特征不能被 lazy@NSCopyingswift怎么读 @NSManagedweaapple storek、 或许 unowned 润饰

二、实践应用

Foil — 对UserDefaults进行了轻量级的特征包装第三方库

这部分我们首要简略的看下该第三方库的中心application完成与运用

1、运用

  • 声明
// 声明运用的key为flagEnabled,默认值为true
@appstoreWrappedDefault(key: "flagEnabled", defaultValue: true)
var flagEnabled: Bool
// 声明运用的key为timestamp
@WrappedDefaultOptional(key: "timestamp")
vswift世界结算体系ar timestamp: Date?
  • 获取
// 获取变量在UserDefault中对应存储的值
self.fappstorelagEnabled
self.timestamp
  • 赋值
// 设置UserDapple idefault中对应存储的值
self.flagEnabled = false
self.timestamp = Date()

2、中心代码

WrappedDefault.swift 文件

@propertyWrapper
public strswiftkeyuct WrappedDefauswiftlylt<T: UserDefaultsSerializable>appstore {
private lappstoreet _userDefaults: Uapp装置下载serDefaults
/// 运用UserDefaults是所运用的app id注册key
public let key: String
/// 从Userapple idDefaults中获取到的值
public var wrappedValue: T {
get {
self._userDefaults.fetch(self.key)approach
}
set {
self._userDefaults.Swiftsave(newValue, forappear: self.key)
}
}
// 初始化办法
public init(
keyName: String,
defaultValue: T,
userDefaults: UserDefaults = .standard
) {
self.key = keyName
self._userDefaulapple idts = userDefaults
// 对key所对应apple pay的值进行初始化(已有值则越过,没有则进行初始化)
uappreciateserDefaults.registerDeAPPfault(value: defaultValue, kappointmentey: keyName)
}
}

WrappedDefaultOptional.swift 文件

@appstorepropertyWrapper
public struct WrappedDefaultOptional<T: UserDefaultsSerapple payializable> {
private let _uapple idserDefaults: UserDefaults
public lswift什么意思et key: String
/// 从UserDefaults中获取到的值,无则回来nil
public var wrappedValueapple store: T? {
get {app store
self._userDefaults.fetchOptional(self.key)
}
set {
if let newValue = newValue {
// 更新值
self._userDefaults.save(applicationnewValue, for: self.key)
} else {
// 删去值
self._userDefaults.delete(for: self.key)
}
}
}
public init(keyName: String,
userDefaults: UserDefaults = .standard) {
self.key = keyName
self.apple tv_userapple tvDefaults = userDefaults
}
}

三、资料

Swift官方文档app id注册

apple / swifapproacht-evolution