可以在类、结构体、协议中定义属性,属性可以是变量,也可以是常量。
1.在结构体中声明属性:
struct RectStore{
var length : Int
var breadth : Int
}
var r = RectStore(length:5,breadth:5)//length = 5
r.length = 6//length = 6
但因为结构体是值引用类型,所以当我们把结构体声明为常量时,是不可以改变结构体内部属性值的。如下:
let r1 = RectStore(length: 5, breadth: 5)
r1.length = 6 //报错:Cannot assign to property: 'r1' is a 'let' constant
2.懒加载
定义为懒加载的属性
struct 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
}
//打印结果:Rect struct hasn't been initialised using the lazy var
var s1 = Square(sidesEqual: true)
if s1.sidesEqual
{
print(s1.r.length)
}
else{
print("Rect struct hasn't been initialised using the lazy var") //not printed
}
//打印结果:Rect struct is initialised now from the lazy var property \n 6
从上面的例子可以看出,懒加载会在调用之前在初始化。
2.1懒加载定义闭包
class Name{
var name : String?
lazy var greet : String = {[weak self] in//为了防止循环引用,我们使用weak self
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)//打印结果:Hi, Anupam
此时,我们把name置空,看看效果
n.name = nil
print(n.greet)//打印结果:Hi, Anupam
发现打印结果没有改变,上述例子表明,懒加载只初始化一次;所以不论变量如何变化,闭包的结果是不变的.
再看个例子:
//在举个例子
var nn = Name(name : "Bobby")
nn.name = nil
print(nn.greet)//打印结果:No name found
nn.name = "Bobby"
print(nn.greet)//打印结果:No name found
声明属性,在属性内部实现get、set方法;实现属性的读写
struct Rectengle{
var length : Double
let breadth : Double
var area : Double{
get{//根据长框,算出面积;当外部直接调用area时,调用
return length * breadth
}
set(newArea){//根据给定的面积、宽,计算出长;当外部给area赋值时调用
length = newArea / breadth
}
}
}
var rs = Rectengle(length:6,breadth:5)
print(rs.area)//打印结果:30.0 调用的是get方法
rs.area = 40
print(r.length)//打印结果:8.0 调用的是set方法
//如果set方法中参数名不明确说明,Swift默认属性名为newValue,可以简化为下面方式
struct RectangleSimply{
var length : Double
let breadth : Double
var area : Double {
get{
return length*breadth
}
set
{
length = newValue/breadth
}
}
}
但是需要注意的是:
1、将实现了get、set方法的属性,定义为lazy var;也不能定义为常量。
2、定义了set方法的属性,必须定义get,不然会报错。
3、定义了get方法的属性,可以不定义set方法,此时,属性只支持读,不支持写。
struct readOnlyRect{
var length : Double
var breadth : Double
var area : Double{
get{
return length * breadth
}
}
//周长
var perimeter : Double{
get{
return length * 2 + breadth * 2
}
}
}
var rr = readOnlyRect(length:6,breadth:5)
print(rr.area)//打印结果:30
rr.area = 40 //报错,因为未实现,set方法;声明变量默认是包含get和set方法,只是读取的是变量本身的值。
3.属性观察者
对属性变化做出响应,包含两个方法:
(1)willSet:在值存储之前触发,它允许我们在值更改之前读取旧值。我们可以使用关键字newValue访问新值。
(2)didSet:在值存储之后触发,它允许我们读取新值和旧值。我们可以使用关键字oldValue访问旧值。
给属性set值时,会触发属性观察者。
struct yardToInchesConversion{
var yard : Double = 0{
willSet{
print("new value of yard \(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
//打印结果:
//new value of yard 22.0
//old value of yards 0.0
//Updated value of inches 792.0
4.全局变量和静态变量
静态变量在子类中不能重写
class A {
var testNumner : Int = 10
static var i : Int = 5
static var name : String{
return "Hello World"
}
class var multiplyByANumber: Int {
return i * 5
}
static func printI(){
print("Value of i is \(i)")
}
class func appendClassName(){
print("Class A Hello World")
}
}
class SubClass : A{
override class var multiplyByANumber : Int{
return i * 5 * 5
}
override class func appendClassName(){
print("Class SubClass Hello World")
}
}
5.subscript
下标是访问集合、列表、序列元素的捷径,我们是用array[index]、dictionary[key]等,相应的,我们可以定义一个任意类型的下标。我们可以为同一类型定义多个下标,并根据传递给下标的索引值的类型选择要使用的适当下标重载。
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"