11个资源强大的网站
@转义(@escaping)
It’s normally used as an escaping
closure passed as a function argument. It exists in the memory when the function ends and then gets executed.
通常用作作为函数参数传递的escaping
闭包。 当函数结束然后执行时,它存在于内存中。
When defining an optional closure as a property, it’s already escaping by default.
在将可选闭包定义为属性时,默认情况下已经在转义。
class Service {
var closure: @escaping (() -> Void)? //error: closure is already escaping in optional type argument
}
The escaping closure can be stored for later use:
可以将转义的闭包存储起来以备后用:
class Service {
var closure: (() -> Void)?
func storageExample(with completion: @escaping (() -> Void)) {
closure = completion // Stored for later use
}
}
Or it can be executed after the function ends:
或者可以在函数结束后执行:
class Service {
func asyncExample(with completion: @escaping (() -> Void)) {
DispatchQueue.global().async { // Excute escaping closure ayncally
completion()
}
}
}
@未知(@unknown)
@unknown
was introduced with @frozen
and @nonfrozen
enumerations. A non-frozen enum may gain new enumeration cases in the future. For instance, the UILayoutConstraintAxis
contains two axes at the moment: AxisHorizontal
and AxisVertical
:
@unknown
是由@frozen
和@nonfrozen
枚举引入的。 非冻结枚举将来可能会获得新的枚举案例。 例如, UILayoutConstraintAxis
包含两个轴: AxisHorizontal
和AxisVertical
:
enum UILayoutConstraintAxis: Int {
case UILayoutConstraintAxisHorizontal = 0
case UILayoutConstraintAxisVertical = 1
}
It may gain another case axisZ
later:
以后可能会获得另一个case axisZ
:
enum UILayoutConstraintAxis: Int {
case UILayoutConstraintAxisHorizontal = 0
case UILayoutConstraintAxisVertical = 1
case UILayoutConstraintAxisZ = 2
}
To safely avoid the compile error:
为了安全地避免编译错误:
error: switch must be exhaustive
We implement the switch with @unknown
attributes:
我们使用@unknown
属性实现开关:
switch axis {
case .UILayoutConstraintAxisHorizontal:
print("")
case .UILayoutConstraintAxisVertical:
print("")
@unknown default:
print("")
}
@propertyWrapper(@propertyWrapper)
When applying a property wrapper to the property of a class, structure, or enumeration, it wraps access to the property through an instance of the wrapper type.
将属性包装器应用于类,结构或枚举的属性时,它将通过包装器类型的实例包装对属性的访问。
The wrapper must define a wrappedValue
, which is the getter and setter for the property exposed. The following example trims whitespaces and newlines from incoming string values:
包装器必须定义wrappedValue
,它是暴露的属性的获取器和设置器。 下面的示例从传入的字符串值中修剪空格和换行符:
@propertyWrapper
struct WhitespaceTrimmable {
private(set) var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.trimmingCharacters(in: .whitespacesAndNewlines) }
}
init(wrappedValue: String) {
self.wrappedValue = wrappedValue
}
}
To use it:
要使用它:
struct Service {
@WhitespaceTrimmable var title: String
}
let service = Service(title: "Title ")
print(service.title) // Title
The property wrapper can accept arguments as default values too:
属性包装器也可以接受参数作为默认值:
struct Service {
@WhitespaceTrimmable(wrappedValue: "Default title") var title: String
}
var service = Service()
print(service.title) // Default title
To access the wrapped property directly, we use _
as a prefix name:
要直接访问包装的属性,我们使用_
作为前缀名称:
struct Service {
@WhitespaceTrimmable(wrappedValue: "Default title") var title: String
func accessTitle() {
print("title: \(_title)") //Default title
}
}
@可用(@available)
It indicates that the declaration is only available in specific Swift language versions or OS system versions.
它表明该声明仅在特定的Swift语言版本或OS系统版本中可用。
For instance, to use the compositional UICollectionView
that is only available in iOS 13+:
例如,要使用仅在iOS 13+中可用的合成UICollectionView
,请执行以下操作:
public struct CollectionViewCellProvider {
@available(iOS 13, *)
public static func compositionalCell() {
// compositional collection view cell
}
public static func collectionCell() {
// collection view cell
}
}
@discardableResult(@discardableResult)
It indicates that the result of the function can be ignored without the compiler warning.
它指示函数的结果可以忽略而无需编译器警告。
Before we apply the @discardableResult
to the function, the compiler complains Result of call to '' is unused
when the function is called without using its result:
在将@discardableResult
应用于函数之前,编译器会抱怨在不使用函数Result of call to '' is unused
的结果未使用:
class ParentViewController: UIViewController {
override func viewDidLoad() {
presentViewController() // Result of call to 'presentViewController' is unused
}
func presentViewController() -> UIViewController {
return UIViewController()
}
}
To silence the warning, we use @discardableResult
:
为了使警告@discardableResult
,我们使用@discardableResult
:
class ParentViewController: UIViewController {
override func viewDidLoad() {
presentViewController() // No Xcode complains!
}
@discardableResult
func presentViewController() -> UIViewController {
return UIViewController()
}
}
@dynamicCallable(@dynamicCallable)
@dynamicCallable
takes @dynamicMemberLookup
a step further. It’s syntactic sugar rather than any sort of compiler magic. It applies to a class, structure, enumeration, or protocol to treat instances of the type as callable functions.
@dynamicCallable
使@dynamicMemberLookup
更进一步。 它是语法糖,而不是任何形式的编译器魔术。 它适用于类,结构,枚举或协议,将类型的实例视为可调用函数。
To use it, we need to add @dynamicCallable
attributes and implement one or both of the following methods:
要使用它,我们需要添加@dynamicCallable
属性并实现以下一种或两种方法:
func dynamicallyCall(withArguments args: ExpressibleByArrayLiteral) -> Double
func dynamicallyCall(withKeywordArguments args: ExpressibleByDictionaryLiteral) -> Double
@dynamicCallable
struct RandomProvider {
func dynamicallyCall(withArguments args: [Int]) -> Double {
let numberOfZeroes = Double(args[0])
let maximum = pow(10, numberOfZeroes)
return Double.random(in: 0...maximum)
}
func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Int>) -> Double {
let numberOfZeroes = Double(args.first?.value ?? 0)
let maximum = pow(10, numberOfZeroes)
return Double.random(in: 0...maximum)
}
}
let random = RandomProvider()
print(random(1)) // 8.15946134247
print(random(a:1)) // 5.14551692644
@dynamicMemberLookup(@dynamicMemberLookup)
It was introduced at the Swift Evolution proposal SE-0195. It instructs Swift to call a subscript
method when accessing properties. We need to add the subscript
method when using it:
它是在Swift Evolution提案SE-0195中引入的。 它指示Swift在访问属性时调用subscript
方法。 使用它时,我们需要添加subscript
方法:
subscript(dynamicMember:)
For the following instance, we implement the User
struct with members firstname
and lastname
. The properties do not exist as properties but are all looked up at runtime. The dynamicMember
looks up the property member firstname
and lastname
in a dictionary and returns its value.
对于以下实例,我们使用成员firstname
和lastname
实现User
结构。 这些属性不作为属性存在,而是在运行时进行查找。 dynamicMember
在字典中查找属性成员的firstname
和lastname
,并返回其值。
@dynamicMemberLookup
struct User {
subscript(dynamicMember member: String) -> String {
let properties = ["firstname": "Bob", "lastname": "Dylan"]
return properties[member, default: ""]
}
}
let user = User()
print(user.firstname) // Bob
print(user.lastname) // Dylan
@主要(@main)
It becomes more practical with the @Argument
attribute in Swift 5.3, especially when creating a Swift CLI tool. It applies to a class, struct, or enum declaration to indicate it contains the top-level entry point. The main()
function must be provided.
使用Swift 5.3中的@Argument
属性,它变得更加实用,尤其是在创建Swift CLI工具时。 它适用于类,结构或枚举声明,以指示它包含顶级入口点。 必须提供main()
函数。
@main
struct Repeat: ParsableCommand {
@Argument(help: "The phrase to repeat.")
var phrase: String
mutating func run() throws {
for _ in 1...5 {
print(phrase)
}
}
}
@UIApplicationMain(@UIApplicationMain)
It’s probably the best-known attribute, as it sits in the AppDelegate.swift
file to indicate the main entry point of the iOS app.
它可能是最著名的属性,因为它位于AppDelegate.swift
文件中,用于指示iOS应用程序的主要入口点。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
}
@NSApplicationMain(@NSApplicationMain)
When we create an OS X project, Xcode generates a main.swift
file. This attribute applies to the app delegate class in order to generate an implicit main for the app. It plays the same role as @UIApplicationMain
for iOS apps.
当我们创建OS X项目时,Xcode会生成一个main.swift
文件。 此属性适用于应用程序委托类,以便为应用程序生成隐式的主体。 对于iOS应用,它的作用与@UIApplicationMain
相同。
import Cocoa
NSApplicationMain(Process.argc, Process.unsafeArgv)
结论(Conclusion)
Swift keeps adding @ attributes in different versions. Understanding and using them correctly and efficiently can bring us clean code and better app performance.
Swift不断在不同版本中添加@属性。 正确有效地理解和使用它们可以为我们带来干净的代码和更好的应用程序性能。
Thank you for reading. Leave any questions you might have in the comments.
感谢您的阅读。 留下您可能在评论中有任何疑问。
All code mentioned above can be found in this GitHub repo.
上面提到的所有代码都可以在此GitHub存储库中找到。
翻译自: https://medium.com/better-programming/10-powerful-attributes-in-swift-d4e4153a0001
11个资源强大的网站