Swift基础入门知识学习(14)-属性-讲给你懂

TED演讲的8个秘诀:学习18分钟高效表达-重点笔记

Swift基础入门知识学习(13)-类&结构体(类别及结构)-讲给你懂


理解难度
★★★★☆
实用程度
★★★☆☆

属性(property)为特定型别(类别、结构或枚举)的值,有以下几种使用方式:

储存属性(stored property):在实例内储存常量或变量,可以用于类别及结构。
计算属性(computed property):在实例内计算一个值,可以用于类别、结构及枚举。
类别属性(type property):与前两个不同,这是属于类别本身的属性。
属性观察器(property observer):用来观察属性值的变化,并以此触发一个自定义的操作。

储存属性

储存属性(stored property)就是一个储存在特定类别(类别或结构)的常量或变量。可以在定义储存属性时指定预设值,也可以在建构过程中设置或修改储存属性的值,以下是个例子:

// 定义一个游戏角色的血量与法力最大值
struct CharacterStats {
    // 指定一个预设值
    var hpValueMax: Double = 300
    let mpValueMax: Double
}

// 或是在建构时设置属性的值
var oneStats = CharacterStats(hpValueMax: 500, mpValueMax: 120)

// 生成实例后也可以再修改属性的值
oneStats.hpValueMax = 200

// 但因为 mpValueMax 为一个结构里的常量属性 所以不能修改常量
// 下面这行会报错误
oneStats.mpValueMax = 200

常量结构的储存属性

如果生成一个结构的实例并指派给一个常量,则无法修改这个实例的任何属性,就算是结构里的储存属性为变量也无法,例子如下:

// 这边使用前面定义的 CharacterStats 结构
// 生成一个 CharacterStats 结构的实例 并指派给一个常量 someStats
let someStats = CharacterStats(hpValueMax: 900, mpValueMax: 150)

// 这个实例 someStats 为一个常量 所以即使 hpValue 为一个变量属性
// 仍然不能修改这个值 这行会报错误
someStats.hpValue = 1200

前面章节有提到过,结构(struct)是属于值类别(value type),所以当实例声明为常量时,其内所有属性也就都是常量而无法修改了。

而相对地,类别(class)是属于参考类别(reference type),一个类别实例的常量,仍可以修改其内的属性,因为这时候这个常量储存的是参考(参考其在记忆体空间内配置的位置),而不是储存这个实例。

延迟储存属性

延迟储存属性(lazy stored property)是指当第一次被呼叫的时候才会计算其初始值的属性。在属性声明前使用lazy来表示一个延迟储存属性。

延迟储存属性只能使用在变量(使用var关键字),因为属性的值在实例建构完成之前可能无法得到,而常量属性在建构完成之前必须要有初始值。

延迟存储属性一般用于:

  • 延迟对象的创建。
  • 当属性的值依赖于其他未知类。
class sample {
    lazy var company = member() // `var` 关键字是必须的
}

class member {
    var name = "Mill Swift 教程"
}

var firstsample = sample()
print(firstsample.company.name)

计算属性

除了储存属性外,类别、结构和枚举还可以定义计算属性(computed property),计算属性不直接储存值,而是提供一个getter(使用关键字get)来存取值,及一个可选( optional 非必须)的setter(使用关键字set)来间接设置其他属性的值。

class sample {
    var no1 = 0.0, no2 = 0.0
    var length = 500.0, breadth = 100.0
    
    var middle: (Double, Double) {
        get{
            return (length / 2, breadth / 2)
        }
        set(axis){
            no1 = axis.0 - (length / 2)
            no2 = axis.1 - (breadth / 2)
        }
    }
}

var result = sample()
print(result.middle)
result.middle = (0.0, 10.0)

print(result.no1)
print(result.no2)

如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValue。

// 将原先的 axis 参数移除 这时会提供一个内建的参数名称 newValue
set{
            no1 = newValue.0 - (length / 2)
            no2 = newValue.1 - (breadth / 2)
        }

唯读计算属性

计算属性的setter是可选( optional 非必须)的,所以依照需求可以只写getter,这时可以将计算属性简化,以下修改自前面定义的类别GameCharacter:

// 定义一个游戏角色的状态
class AnotherGameCharacter {
    // 血量初始值
    var hpValue: Double = 100

    // 防御力初始值
    var defenceValue: Double = 500

    // 总防御力只有 getter
    var totalDefence: Double {
        // 总防御力的算法是 防御力加上 10% 血量
        return (defenceValue + 0.1 * hpValue)
    }

}

上述程式中,因为计算属性只有getter,所以getter可以省略掉关键字get及大括号{ }。

要注意必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。

属性观察器

属性观察器(property observer)会监控和回应属性值的变化,每次属性被设置新的值都会呼叫属性观察器。以下为两个可以使用的属性观察器:

  1. willSet:在设置新的值之前呼叫,会将这个新的值当做一个常量参数传入,如果不命名这个参数名称时,会有一个内建的参数名称newValue。
  2. didSet:在新的值被设置之后立即呼叫,会将旧的属性值当做参数传入,这个参数可以自己命名,或直接使用内建的参数名称oldValue。
    willSet和didSet观察器在属性初始化过程中不会被调用
class Samplepgm {
    var counter: Int = 0{
        willSet(newTotal){
            print("计数器: \(newTotal)")
        }
        didSet{
            if counter > oldValue {
                print("新增数 \(counter - oldValue)")
            }
        }
    }
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

类别属性

类别属性(type property)是属于这个型别(类别、结构或枚举)的属性,无论生成了多少这个类别的实例,类别属性都只有唯一一份。

类别属性使用于定义所有从这个类别生成的实例共享的资料。

  • 储存型的类别属性一定要有预设值,因为类别本身没有建构器,无法在初始化过程中设值给类别属性。
  • 储存型的类别属性是延迟初始化的,只有在第一次被呼叫时才会被初始化,所以不需要对其使用lazy。
  • 类别属性是使用static关键字作声明变量或常量。

在为类别声明计算型的类别属性时,依照需求可以改用关键字class来支持子类别对父类别的实作覆写(override),也就是在将一个类别A的计算型的类别属性以class声明后,之后新的类别B继承这个类别A时,可以覆写这个类别属性。

struct Structname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // 这里返回一个 Int 值
   }
}

enum Enumname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // 这里返回一个 Int 值
   }
}

class Classname {
   class var computedTypeProperty: Int {
      // 这里返回一个 Int 值
   }
}

例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。

存取或设置类别属性的值

与实例的属性一样,类别属性的存取也是使用点语法(dot syntax),但是类别属性是向类别本身存取和设置,而不是向实例,例子如下:

struct StudMarks {
   static let markCount = 97
   static var totalCount = 0
   var InternalMarks: Int = 0 {
      didSet {
         if InternalMarks > StudMarks.markCount {
            InternalMarks = StudMarks.markCount
         }
         if InternalMarks > StudMarks.totalCount {
            StudMarks.totalCount = InternalMarks
         }
      }
   }
}

var stud1Mark1 = StudMarks()
var stud1Mark2 = StudMarks()

stud1Mark1.InternalMarks = 98
print(stud1Mark1.InternalMarks) 

stud1Mark2.InternalMarks = 96
print(stud1Mark2.InternalMarks)

Swift基础入门知识学习(15)-方法-讲给你懂

高效阅读-事半功倍读书法-重点笔记-不长,都是干货

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MillVA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值