一个属性包装器,允许你强制闭包被精确地调用一次。在 SE-0293 引入后,这尤其有用,因为它使得将属性包装器放在函数和闭包参数上成为合法操作。
在编写代码时,你经常会遇到带有完成处理程序的函数,这些完成处理程序必须根据函数执行的底层结果,使用成功或失败值来调用。但是,如果你不小心,就很容易犯错,例如根本不调用完成处理程序,或者多次调用它,尤其是在存在复杂的业务逻辑或错误处理时。
func fetchSpecialUser(@Once completion: @escaping (Result<User, Error>) -> Void) {
fetchUserImpl { user in
guard let user = user else {
// oops, forgot to call completion(...) here!
return
}
guard user.isPendingEmailVerification == false else {
completion(.failure(.userNotVerified))
return
}
if user.hasSubscription {
switch getSubscriptionType(user) {
case .ultimate, .premium:
completion(.success(user))
case .standard:
completion(.failure(.noPaidSubscription))
}
}
// ... more business logic here
// oops, forgot a 'return' in the if-statement above,
// so execution continues and closure is called twice
// (and with an invalid result!).
completion(.failure(.generic))
}
只需使用 @Once
注解你的函数参数,如果闭包根本没有被调用,或者被调用了多次,你将会得到一个运行时错误。
func fetchSpecialUser(@Once completion: @escaping (Result<User, Error>) -> Void) {
fetchUserImpl { user in
guard let user = user else {
// runtime error: expected closure to have already been executed once!
return
}
guard user.isPendingEmailVerification == false else {
completion(.failure(.userNotVerified))
return
}
if user.hasSubscription {
switch getSubscriptionType(user) {
case .ultimate, .premium:
completion(.success(user))
case .standard:
completion(.failure(.noPaidSubscription))
}
}
// ... more business logic here
// runtime error: closure has already been invoked!
completion(.failure(.generic))
}
@escaping
注解它。 这不是最理想的,但由于闭包存储在属性包装器内部,因此无法告诉编译器该闭包不会逃逸,即使你确切地知道它不会逃逸(也许是因为你的代码是同步的)。将以下内容添加到你项目的 Package.swift
文件中
.package(url: "https://github.com/theblixguy/Once", from: "0.0.1")
或者通过 Xcode 界面添加此软件包,方法是转到 File > Swift Packages > Add Package Dependency。
MIT License
Copyright (c) 2021 Suyash Srijan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.