Swift(十五)属性

星空

计算属性和存储属性

我们知道在OC中, 使用@ property声明的实例变量, 都会自动生成setter和getter方法, 但是在swift中, 属性分为计算属性和存储属性, 存储属性存储常量或变量作为实例的一部分,计算属性计算(而不是存储)一个值,就是setter和getter方法, 除存储属性外,类、结构体和枚举可以定义计算属性,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。

延迟存储属性

延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用lazy(xcode8)不是@lazy来标示一个延迟存储属性。类似于OC中的懒加载

注意:必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到(意思就是说, 延迟属性, 不需要在创建实例时赋初始值)。而常量(使用var)属性在构造过程完成之前必须要有初始值(如果你不给初始值, 编译器会根据类型推断, 自动分配),因此无法声明成延迟属性。

class DataImporter { 
    /* 
    DataImporter 是一个将外部文件中的数据导入的类。 
    这个类的初始化会消耗不少时间。 
    */ 
    var fileName = "data.txt" 
    // 这是提供数据导入功能 
} 
 
class DataManager { 
    lazy var importer = DataImporter()  //延迟属性, 用到的时候才回去加载
    var data = String[]() 
    // 这是提供数据管理功能 
} 

计算属性

//结构体
struct Point { 
    var x = 0.0, y = 0.0 
} 
//结构体
struct Size { 
    var width = 0.0, height = 0.0 
} 
//结构体
struct Rect { 
    var origin = Point() 
    var size = Size() 
    var center: Point { 
//getter方法
    get { 
        let centerX = origin.x + (size.width / 2) 
        let centerY = origin.y + (size.height / 2) 
        return Point(x: centerX, y: centerY) 
    } 
//setter方法, newCenter为setter方法的参数
    set(newCenter) { 
        origin.x = newCenter.x - (size.width / 2) 
        origin.y = newCenter.y - (size.height / 2) 
    } 
    } 
} 
//声明一个结构体
var square = Rect(origin: Point(x: 0.0, y: 0.0), 
    size: Size(width: 10.0, height: 10.0)) 
let initialSquareCenter = square.center  //getter方法, 获取center
square.center = Point(x: 15.0, y: 15.0)  //setter方法, 设置新的center
print("square.origin is now at (\\(square.origin.x), \\(square.origin.y))") 

只读计算属性

只有 getter 没有 setter 的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。(类比OC属性修饰readonly)
注意:必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。

struct Cuboid { 
    var width = 0.0, height = 0.0, depth = 0.0 
    var volume: Double { //只读计算属性的声明可以去掉get关键字和花括号:

    return width * height * depth 
    } 
} 
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) 
print("the volume of fourByFiveByTwo is \\(fourByFiveByTwo.volume)") 

属性监视器

属性监视器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性监视器,甚至新的值和现在的值相同的时候也不例外. (类似于KVO, 但是比KVO方便多了)
可以为属性添加如下的一个或全部监视器:

willSet在设置新的值之前调用
didSet在新的值被设置之后立即调用
willSet监视器会将新的属性值作为固定参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。

类似地,didSet监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。

注意:willSet和didSet监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。

class StepCounter { 
    var totalSteps: Int = 0 { 
    willSet(newTotalSteps) {  //willSet监视器将表示新值的参数自定义为newTotalSteps
        print("About to set totalSteps to \\(newTotalSteps)") 
    } 
    didSet { 
        if totalSteps > oldValue  {  //didSet没有提供自定义名称,所以默认值oldValue表示旧值的参数名。
            print("Added \\(totalSteps - oldValue) steps") 
//注意:如果在didSet监视器里为属性赋值,这个值会替换监视器之前设置的值。
        } 
    } 
    } 
} 
let stepCounter = StepCounter() 
stepCounter.totalSteps = 200  //设置新值, 调用willSet
// About to set totalSteps to 200 
// Added 200 steps 
stepCounter.totalSteps = 360 
// About to set totalSteps to 360 
// 

类型属性

实例的属性属于一个特定类型实例,每次类型实例化后都拥有自己的一套属性值,实例之间的属性相互独立。

也可以为类型本身定义属性,不管类型有多少个实例,这些属性都只有唯一一份。这种属性就是类型属性。

类型属性用于定义特定类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。

对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。

值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。

注意:跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。

//结构体
struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 10
        // 这里返回一个 Int 值
    }
}
//枚举
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        // 这里返回一个 Int 值
        return 20
    }
}
//类
class SomeClass {
//这里在xcode8里, class改为static也可以(目前测试, 结果都是对的, 可能还有没有考虑到的情况)
    class var computedTypeProperty: Int {
        // 这里返回一个 Int 值
        return 30
    }
}
print(SomeStructure.computedTypeProperty) //10
print(SomeStructure.computedTypeProperty) //20
print(SomeClass.computedTypeProperty) //30

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容