Swift属性
在本教程中,我们将讨论Swift属性。
属性是Swift中类,结构和枚举的重要组成部分。
Swift属性
Swift属性大致分为两种类型。
- 存储的属性:存储常量和变量,由类和结构提供
- 计算属性:计算值而不是存储值。
由类结构和枚举提供。
注意:计算所得的属性不能为常数。
Swift存储属性示例
下面给出了一个存储属性的例子。
struct Rect{ var length : Int let breadth : Int } var r = Rect(length: 5, breadth: 5) r.length = 6
长度和宽度都是上述代码段中存储的属性(分别为变量和常数)。
修改常量结构实例
let r1 = Rect(length: 5, breadth: 5) r1.length = 6 //compile-time error.
如果将结构初始化为常量,则即使将其声明为变量,也无法更改存储的属性。
原因是结构是值类型。
由于类是引用类型,因此情况并非如此。
Swift Lazy属性
根据Apple的文档,Swift Lazy属性定义为:
与其他属性不同,惰性属性是在首次访问之前初始化的。
当防止不必要的对象创建并随后节省内存时,惰性属性很有用。
通常,当某个属性依赖于其他未知属性时,它被定义为惰性。
惰性修饰符不能添加到常量。
常数在初始化完成之前需要一个初始值,而懒惰属性则并非如此。惰性属性必须具有初始化程序,不能简单地与任何变量一起使用。
以下是lazy var
的错误用法情况。
struct Rect{ lazy var length : Int //compile-time error. lazy properties require an initaliser. let breadth : Int }
下面是lazy var的示例:
truct Rect{ var length : Int let breadth : Int init(length : Int, breadth: Int) { print("Rect struct is initialised now from the lazy var property") self.length = length self.breadth = breadth } } struct Square{ var sidesEqual : Bool lazy var r = Rect(length: 6, breadth: 6) init(sidesEqual : Bool) { self.sidesEqual = sidesEqual } } var s = Square(sidesEqual: false) if s.sidesEqual { print(s.r.length) } else{ print("Rect struct hasn't been initialised using the lazy var") //this gets printed } var s1 = Square(sidesEqual: true) if s1.sidesEqual { print(s1.r.length) //prints Rect struct is initialised now from the lazy var property \n 6 } else{ print("Rect struct hasn't been initialised using the lazy var") //not printed }
从上面的代码中可以明显看出,只有在满足条件时才从惰性var实例实例化Rect结构。
当代码中有许多对象实例时,惰性属性非常方便,因为只有在需要时才创建声明的实例。
一旦初始化了惰性属性,为了进行进一步的访问,它通常会重用第一个实例。
注意:如果标记有lazy修饰符的属性同时被多个线程访问,并且该属性尚未初始化,则不能保证该属性仅被初始化一次。
闭包的Swift Lazy属性
class Name { var name : String? lazy var greet : String = {[weak self] in guard let s = self else { return "Unable to unwrap self"} guard let n = s.name else { return "No name found" } return "Hi, \(n)" }() init(name: String) { self.name = name } } var n = Name(name: "Anupam") print(n.greet) //prints "Hi, Anupam\n"
重要事项
在上面的代码中,我们在lazy var属性内定义了一个闭包。
闭包返回一个字符串。
为了消除强大的参考周期,我们捕获了一个"弱自我"。
" guard let"用于可选的展开。
让我们对上面的代码进行一些修改,看看它的行为。
var n = Name(name: "Anupam") print(n.greet) //prints "Hi, Anupam" n.name = nil print(n.greet) //prints "Hi, Anupam"
上面的代码片段是一个有趣的案例,它表明lazy var属性每次都被重用。
对name
属性的更改没有任何作用。
var n = Name(name: "Anupam") n.name = nil print(n.greet) //prints "No name found"
在以上代码段中,第二个保护let语句未能解开可选字符串。
Swift计算属性
与"存储的"不同,"计算的属性"不存储值。
而是将它们用作获取程序和可选的设置程序,以间接检索和设置其他属性和值。
下面给出一个基本示例。
struct Rect{ var length : Double let breadth : Double var area : Double { get{ return length*breadth } set(newArea) { length = newArea/breadth } } } var r = Rect(length: 6, breadth: 5) print(r.area) //prints 30.0 r.area = 40 print(r.length) //prints 8.0
在上面的代码中,将getter和setter用作计算属性" area"上的" get {}"和" set(param_name){}"。
使用点语法访问getter和setter。
如果未在设置器中指定参数名称,则Swift会将默认名称分配为" newValue"。
struct Rect{ var length : Double let breadth : Double var area : Double { get{ return length*breadth } set { length = newValue/breadth } } }
无法将计算属性分配为惰性var属性。
定义了get和set的计算属性不能设置为常量" let"。
只读计算属性
不带setter的Compulated属性是只读的计算属性。
它们可以定义为常量。
struct Rect{ var length : Double let breadth : Double var area : Double { get{ return length*breadth } } } var r = Rect(length: 6, breadth: 5) r.area = 50 //compile-time error. area is a get-only property.
在上述情况下,我们也可以放开get关键字:
var area : Double { return length*breadth }
Swift属性观察员
Swift属性观察者响应属性值的更改。
这些属性通常在两个属性值相互依赖时使用。
它们包含两种方法:
willSet:这将在存储值之前触发。
它允许我们在更改之前读取旧值。
我们可以使用关键字newValue
访问新值。didSet:在存储值后触发。
它使我们能够读取旧值和新值。
我们可以使用关键字" oldValue"访问旧值
每次设置该值都会触发属性观察器。
让我们在需要将码转换为英寸的示例中使用属性观察器。
struct yardToInchesConversion{ var yard : Double = 0 { willSet{ print("new value of yards \(newValue)") } didSet{ print("old value of yards \(oldValue)") inches = yard*36 print("Updated value of inches \(inches)") } } var inches : Double = 0 } var yi = yardToInchesConversion() yi.yard = 22 //The Following gets printed on the console: new value of yards 22.0 old value of yards 0.0 Updated value of inches 792.0
Swift的全局和本地属性
全局变量是在任何函数,方法,闭包或者类型上下文之外定义的变量。
局部变量是在函数,方法或者闭包上下文中定义的变量。
全局常量和变量始终是惰性计算的,无需使用惰性修饰符进行标记。
Swift类型属性
类型属性用于类型(类/结构/枚举),而不是该类型的实例。
类型属性是用关键字" static"定义的。
静态类型属性不能在子类中覆盖。
在这种情况下,关键字" class"用于计算的属性。存储的属性不支持
class
关键字。
以下代码段清楚地说明了上述概念。
class A { static var i : Int = 5 static var name : String { return "Hello World" } class var multiplyByANumber : Int { return i*5 } //class var j : Int = 1 //不支持. Won't compile. static func printI() { print("Value of i is \(i)") } class func appendClassName() { print("Class A Hello World") } } class SubClass : A { //static var i = 10 Won't Compile override class var multiplyByANumber : Int{ return i*5*5 } override class func appendClassName(){ print("Class SubClass Hello World") } }
以上程序的输出:
Class A Hello World 25 Class SubClass Hello World 125
Swift下标
Swift下标是访问集合,列表或者序列的成员元素的快捷方式。
要访问数组,字典或者列表中的元素,我们使用array [index],dictionary [key]等形式。
类似地,我们可以为任何类型定义下标。
我们可以为同一类型定义多个下标,并根据传递给下标的索引值的类型来选择要使用的适当下标重载。
下标的语法类似于如下所示的计算属性。
subscript(index: Int) -> Int { get { //return an appropriate subscript value here } set(newValue) { //perform a suitable setting action here } }
下标的示例实现如下所示。
class M { private var month = ["Jan", "Feb", "March", "April"] subscript(index: Int) -> String { get { return month[index] } set(newValue) { self.month[index] = newValue } } } var m = M() m[3] //April m[0] = "Dec"