当前位置:网站首页>Swift - 标红的修饰词
Swift - 标红的修饰词
2022-07-22 22:54:00 【荒唐的天梯】
访问控制 Access Control
open
public
internal
fileprivate
private
open/public可以在任何模块中访问使用,即可以使用import在其他模块中访问,其中open只能修饰class类型,public既可以修饰class类型,也可以修饰struct/enum类型internal默认访问权限,可以在当前模块中访问,不能在其他模块中使用fileprivate可以在当前文件中被访问,在其他文件中不能被访问private可以在当前class以及struct/enum中被访问,其他类中不能被访问
import
关于引入框架,我觉得很多人都在找类似 OC 中 prefix 的文件,但是没找到,其实 Swift 中是存在这种方法的
@_exported import SDWebimage
众所周知,带有_ 的语句为未确定语句
将上面的代码放在 @main 函数执行的文件中进行引入,那么在当前模块中都无线再进行引入,可以直接使用
重命名与关联对象
typealias
typealias 用来对已经存在的类型重新定义新名字,通过命名,可以是代码变得更加清楚简洁。
typealias success = (_ data: String) -> Void
typealias ViewType = UIView
associatedType
associatedType 用来定义一个名字,也可以确定类型,具体使用的值需要用 typealias 来确定,一般在 protocol 中使用。
protocol Network {
associatedType DataType // 没确定类型
associatedType ViewType: UIView // 确定类型,实现时可以使用其子类
}
class Model: Network {
typealias DataType = String
typealias ViewType = UILabel
}
方法返回值
@discardableResult 一般用在有返回值的方法前,含义是,调用当前方法时,可以不使用对象去接收
func getName() -> String {
}
// 当调用该方法时需要使用对象承接
let name = getName()
// 或者
let _ = getName()
而如果不使用对象去接收时,编译器则会报告警告️,因此使用 @discardableResult 将警告消除
@discardableResult func getAge() -> Int {
}
getAge()
关于继承
只有 class 类型可以被继承这个概念不用我多说吧,那么就来说说继承之后的事
override覆盖父类的方法或属性,如覆盖父类的init方法
override init() {
// 必须要执行父类的init方法
// 其中子类自定义的属性要放在 super.init() 方法前执行
super.init()
// 子类修改父类的属性要放在 super.init() 方法后执行
}
// 覆盖属性父类属性要使用计算属性覆盖
override var name: String {
get {
return ""
}
set {
}
}
convenience用于修饰init方法,为便利构造器,可以override convenience覆盖父类的便利构造器,方法中必须执行当前子类的构造器
override init() {
}
override convenience init(name: String) {
self.init()
self.name = name
}
required子类必须重写的init方法
required init(_ sex: String) {
fatalError("init(_:) has not been implemented")
}
动态成员查找
@dynamicMemberLookup 是在Swift 4.2 中增加的新特性,即动态成员查找。在使用了 @dynamicMemberLookup 修饰对象后(class、struct、enum、protocol),并且实现了 subscript(dynamicMember member: String) 方法后就可以方为不存在的属性,而属性就会作为 member 传入这个方法。
@dynamicMemberLookup
struct Person {
subscript(dynamicMember member: String) -> String {
let properties = ["nickname": "Zhang", "city": "BeiJing"]
return properties[member, default: "nil"]
}
}
// 执行
let p = Person()
print(p.city)
print(p.nickname)
print(p.name)
如果没有声明 @dynamicMemberLookup ,执行代码会报错
如果实现了多个 subscript(dynamicMember member: String) 方法时,需要在执行时执行返回类型
@dynamicMemberLookup
struct Person {
subscript(dynamicMember member: String) -> String {
let properties = ["nickname": "Zhang", "city": "BeiJing"]
return properties[member, default: "nil"]
}
subscript(dynamicMember member: String) -> Int {
return 18
}
}
let p = Person()
let age: Int = p.age
print(age) // 18
@dynamicMemberLookup 内部处理
a = someValue.someMember
==>
a = someValue[dynamicMember: "someMember"]
动态传参
@dynamicCallable ,当对象被 @dynamicCallable 标记后,需要实现两个必要方法中的某一个或者两个来进行动态传参。
// 其中数组中的数据类型及返回类型可替换成其他类型
func dynamicallCall(withArguments args: [String]) -> Double
// 其中KeyValuePairs中的数据类型及返回类型可替换成其他类型
func dynamicallCall(withKeywordArguments args: KeyValuePairs<String, Int>) -> Double
使用方法
@dynamicCallable
struct Random {
// func generate(numberOfZeros: Int) -> Double {
// let max = pow(10, Double(numberOfZeros))
// return Double.random(in: 0...max)
// }
func dynamicallyCall(withArguments: [Int]) -> Double {
return 12.0
}
func dynamicallyCall(withKeywordArguments args: [String: Int]) -> Double {
let numberOfZeros = Double(args.first?.value ?? 0)
let max = pow(10, Double(numberOfZeros))
return Double.random(in: 0...max)
}
}
// 调用
let random = Random()
// let result = random.dynamicallyCall(withKeywordArguments: ["numberOfZeros": 3])
let result = random(number: 3) // 调用 withKeywordArguments 方法
let result = random(3) // 12.0 调用 withArguments 方法
print(result)
@dynamicCallable 使用时需要注意一些重要规则
- 可以将其应用于
class、struct、enum和protocol - 如果使用 withKeywordArguments: 并且不使用 withArguments: 你的类型仍然可以在没有参数标签的情况下调用 - 只不过会获得空字符串的键(
key) - 如果
withKeywordArguments: / withArguments:被标记为throwing,则调用类型也将throwing - 不能将
@dynamicCallable添加到扩展,只能添加到类型本身 - 你仍然可以向类型添加其他方法和属性,并正常使用。
Swift 的野心
Swift 之所以做出 @dynamicMemberLookup 和 @dynamicCallable ,其根本原因在于 Swift 不仅仅将视线放在了 C 与 OC 的互通上,也将目光放在了将来与 Python、JavaScript 等动态语言一起工作。
属性包装器
@propertyWrapper 属性包装器的目的就是为了能够给属性一个统一的入口和出口,方便我们进行操作。比如当我们想监听属性时,需要在每个属性中做监听,而属性包装器可以将监听做成统一入口。
对于 @propertyWrapper,有两个要求:
- 必须使用
@propertyWrapper进行定义 - 必须具有
wrappedValue属性
@propertyWrapper
struct Random<T> {
var wrappedValue: T
}
// 使用
@Random var r: Int = 0
// 或者
@Random(wrappedValue: 0) var r
// 或者
var r: Randow = Random(wrappedValue: 0)
/// 三种方法均可,通常使用第一种
系统定义好的属性包装器有 @State, @Binding, @Published, @ObservedObject, @StateObject, @EnvironmentObject, @Environment等。
// 关于在SwiftUI中有重大问题,将单列一篇文章来讲
@State private var height: CGFloat? // 在实际使用中有重大问题
使用限制
- 具有包装器的属性不能再子类中覆盖
- 具有包装器的属性不能有
lazy,@NSCoping,@NSManaged,weak或unowned修饰 wrappedValue,init(wrappedValue:)和projectedValue必须具有与包装类型本身相同或高级(并不生效)的访问控制级别- 不能再协议或扩展中声明带有包装器的属性
Where
where 在定义泛型的类中会被经常使用,
// 泛型
struct Stack<Element> {
}
// 如果要求泛型是某一特殊类型时
extension Stack where Element == String {
}
// 如果要求泛型遵循某一协议时
extension Stack where Element: Equatable {
}
// 定义非默认泛型
struct Sildeshow<Data, ID, Content>: View where Data: RandomAccessCollection, ID: Hashable, Content: View {
}
// 上面的定义可以写成
struct Sildeshow<Data: RandomAccessCollection, ID: Hashable, Content: View>: View {
}
边栏推荐
猜你喜欢
随机推荐
uni-app进阶之内嵌应用【day14】
TextView展示不完的内容实现--全显示、部分显示
Genesis公链:夯实Web 3.0发展底座
Typescript对象扩展之对象原型__proto__与prototype
appendToFile追加失败
Android安全专题-so逆向入门和使用ida动态调试
【JS 逆向百例】某公共资源交易网,公告 URL 参数逆向分析
PIP update a package
传统银行票据打印系统几个关键技术点简要分析
小红书携手HMS Core,畅玩高清视界,种草美好生活
类和对象上案例
Cloud computing may become a new inflection point in the era? From which point can we see?
Tensorrt plug-in practice (1)
Flink高级API(三)
Redis transaction and locking mechanism
Google Earth engine app - a complete map legend app (land use classification of western United States)
构造函数的初始化、清理及const修饰成员函数
算法---使用最小花费爬楼梯(Kotlin)
哪种类型的模切机可用于纸?
黑马程序员-接口测试-四天学习接口测试-第二天-接口用例设计,测试点,功能测试,安全测试,性能测试,单接口测试,业务场景测试用例,postman简介,安装


![[reading notes > statistics] 12-01 construction of confidence interval - Introduction to the concept of confidence interval](/img/27/0431eeedbffdba1bdf4bb015082219.png)






