Swift 属性怎么用?Swift Properties 详解和实际应用

文章导读
上一个 测验 下一个 属性是与特定 class、structure 或 enumeration 相关的变量或常量。它们通常用于定义 class、structure 或 enumeration 实例的特征。属性可以进一步分为 Stored properties 和 Compu
📋 目录
  1. Stored Properties
  2. 惰性存储属性
  3. 实例变量
  4. 计算属性
  5. 属性观察器
  6. 属性包装器
  7. 局部和全局变量
  8. 类型属性
A A

Swift - 属性



上一个
测验
下一个

属性是与特定 class、structure 或 enumeration 相关的变量或常量。它们通常用于定义 class、structure 或 enumeration 实例的特征。属性可以进一步分为 Stored properties 和 Computed properties。Stored properties 用于存储常量和变量值作为实例,而 computed properties 用于计算值而不是存储值。

Stored 和 Computed properties 都与实例类型相关联。当属性与其类型值相关联时,则定义为 'Type Properties'。Stored 和 computed properties 通常与特定类型的实例相关联。然而,属性也可以与类型本身相关联。此类属性被称为 type properties。

Stored Properties

Stored property 将常量或变量值作为特定 class 或 structure 实例的一部分进行存储。它们可以是 variable stored property 或 constant stored property。常量的 stored properties 由 'let' 关键字定义,变量的 stored properties 由 'var' 关键字定义。

在定义 stored property 时,我们可以提供默认值。此外,在初始化时,我们可以初始化和修改 stored property 的初始值。

语法

以下是 stored property 的语法 −

struct structureName{
   var propertyName = initialValue
   let propertyName = initialValue
}

示例

Swift 程序演示 structure 中的属性。

// Structure
struct Number {

   // 没有默认值的 Stored Property
   var digits: Int
    
   // 具有默认值的 Stored Property
   let pi = 3.1415
}
// Structure 的实例
var n = Number(digits: 12345)

// 为属性赋值
n.digits = 67

// 访问 structure 的属性
print("\(n.digits)")
print("\(n.pi)")

输出

它将产生以下输出 −

67
3.1415

示例

拥有 stored property 的另一种方法是使用 constant structures。这样,整个 structure 实例将被视为 '常量 Stored Properties'。

// Structure 
struct Number{

   // Variable Stored Properties
   var digits: Int
    
   // Constant stored property
   let numbers = 3.1415
}

// Structure 的常量实例
let n = Number(digits: 12345)

// 访问 structure 的属性
print("\(n.digits)")
print("\(n.numbers)")

/* Structure 是一种 value type,因此当 structure 的实例被标记为常量类型时,
   该 structure 的所有属性也被视为常量,因此即使它们是 variable 类型,
   我们也无法更改属性的值。但这种情况在 class 中不会发生,
   因为 class 是一种 reference type
*/
n.numbers = 8.7

输出

它将产生以下输出 −

main.swift:25:3: error: cannot assign to property: 'numbers' is a 'let' constant
n.numbers = 8.7
~~^~~~~~~
main.swift:8:4: note: change 'let' to 'var' to make it mutable
   let numbers = 3.1415
   ^~~
   var

它不会将 'number' 重新初始化为 8.7,而是返回错误消息,表明 'number' 被声明为常量。

惰性存储属性

Swift 提供了一种灵活的属性,称为“Lazy Stored Property”,其初始值在第一次使用时才会被计算。此类属性在属性初始值创建成本较高、初始值不需要立即使用等情况下非常有用。

要将存储属性声明为惰性存储属性,必须在变量声明前使用 lazy 修饰符。此外,惰性属性始终是变量类型,因为惰性属性的初始值可能在实例初始化完成之前无法获取。而常量属性在初始化之前总是有值,且我们无法更改常量属性的值,因此不允许将其声明为惰性属性。

语法

以下是惰性存储属性的语法 −

class structureName{
   lazy var propertyName = 
}

示例

Swift 程序演示类中的惰性属性。

// 定义一个名为 'sample' 的类
class Sample {
    
   // 类型为 'number' 的惰性属性
   lazy var no = Number()
}

// 定义一个名为 'number' 的类
class Number {
    
   // 属性 
   var name = "Swift"
}

// 创建 'Sample' 类的实例
var firstSample = Sample()

// 访问惰性属性 'no',然后访问其 'name' 属性
print(firstSample.no.name)

输出

它将产生以下输出 −

Swift

实例变量

在 Objective-C 中,存储属性还具有实例变量用于备份目的,以存储在存储属性中声明的值。

Swift 4 将这两个概念整合到一个单一的“stored property”声明中。与具有对应的实例变量和备份值的存储属性不同,“stored property”在单一位置包含所有整合信息,通过变量名、数据类型和内存管理功能定义变量属性。

计算属性

除了存储属性外,Swift 还支持另一种类型的属性,即计算属性。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter 来间接获取和设置其他属性及值。其中,getter 方法在访问属性时被调用,setter 方法在修改属性时被调用。

要声明计算属性,必须始终使用 var 关键字,后跟属性名、类型以及包含 getter 和 setter 的花括号{}。

语法

以下是计算属性的语法 −

struct structureName{
   var propertyName : propertyType{
      get{}
      set{}
   }
}

示例

Swift 程序演示 class 中的计算属性。

// 类
class sample {

   // 存储属性
   var no1 = 0.0, no2 = 0.0
   var length = 300.0, breadth = 150.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) 

输出

它将产生以下输出 −

(150.0, 75.0)
-150.0
-65.0

当计算属性将新值留为空时,将为该特定变量设置默认值。

作为只读属性的计算属性

计算属性中的只读属性定义为具有 getter 但没有 setter 的属性。它始终用于返回一个值。这些变量可以通过 '.' 语法进一步访问,但不能设置为其他值。

示例

class film {
   var head = ""
   var duration = 0.0
   
   // 作为只读属性的计算属性
   var metaInfo: [String:String] {
      return [
         "head": self.head,
         "duration":"\(self.duration)"
      ]
   }
}

// 类的实例
var movie = film()

// 初始化和访问属性
movie.head = "Swift Properties"
movie.duration = 3.09
print(movie.metaInfo["head"]!)
print(movie.metaInfo["duration"]!)
输出

它将产生以下输出 −

Swift Properties
3.09

属性观察器

属性观察器允许我们观察并响应属性值的变化。每当属性值被设置时,即使新值等于当前值,属性观察器仍会被调用。

属性观察器适用于存储属性和计算属性,并且无论属性是定义的还是继承的都可用。对于继承属性(无论是存储属性还是计算属性),可以通过重写继承类或子类中指定的属性来添加属性观察器;对于定义的计算属性,我们可以使用属性 setter 而非属性观察器。

Swift 支持两种类型的属性观察器 −

  • willSet − 在属性值被存储之前立即调用。它传递一个常量参数作为属性的新值。我们可以在 willSet 的实现中指定参数名称。如果不提供参数名称,则会提供默认参数名为 newValue,表示给定属性的新值。

  • didSet − 在属性新值被设置后立即调用。它传递一个常量参数,包含属性的旧值。我们可以在 didSet 的实现中指定参数名称。如果不提供参数名称,则会提供默认参数名为 oldValue,表示给定属性的旧值。

示例

// 定义类
class Samplepgm {
   var counter: Int = 0{
    
      // willSet 属性观察器
      willSet(newTotal){
         print("Total Counter is: \(newTotal)")
      }
        
      // didSet 属性观察器
      didSet{
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

// 类的实例
let NewCounter = Samplepgm()

// 访问属性
NewCounter.counter = 100
NewCounter.counter = 800

输出

它将产生以下输出 −

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

属性包装器

在 Swift 中,属性包装器用于在管理属性存储方式的代码和定义属性的代码之间添加一层。或者说,属性包装器用于以可重用方式封装属性行为。它们通常用于为属性添加额外功能。@propertyWrapper 属性用于定义属性包装器。

示例

@propertyWrapper
struct Ten {
   private var num = 0
   var wrappedValue: Int {
      get { return num}
      set { num = min(newValue, 18) }
   }
}

struct Rectangle {
   @Ten var length : Int
   @Ten var height : Int
}

var obj = Rectangle()
print(obj.length)

obj.length = 11
print(obj.length)

输出

它将产生以下输出 −

0
11

局部和全局变量

局部和全局变量用于计算和观察属性。

局部变量 全局变量
在 function、method 或 closure 上下文中定义的变量。 在 function、method、closure 或 type 上下文之外定义的变量。
用于存储和检索值。 用于存储和检索值。
使用存储属性来获取和设置值。 使用存储属性来获取和设置值。
也使用计算属性。 也使用计算属性。

类型属性

正如我们所知,实例属性总是属于指定类型的实例。因此,每当我们创建一个新实例时,它总是包含一组属性值,并且这些值与其他实例是分开的。

然而,有时我们希望有一个属于类型本身的属性,而不是属于任何实例。因此,这个问题通过类型属性来解决。类型属性是一种特殊的属性,它属于类型本身,无论创建了多少该类型的实例,它都只有一个副本。存储的类型属性可以是常量或变量,而计算的类型属性总是变量。

类型属性在类型的定义部分使用大括号 {} 定义,变量的作用域也事先定义。对于值类型,使用 'static' 关键字来定义类型属性;对于类类型,使用 'class' 关键字。

语法

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 值
   }
}

查询和设置属性

就像实例属性一样,类型属性使用 '.' 语法进行查询和设置,只需直接在类型上使用,而不是指向实例。

示例

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 = 87
print(stud1Mark2.InternalMarks)

输出

它将产生以下输出 −

97
87