Swift - 屬性



屬性是與特定類、結構體或列舉相關的變數或常量。它們通常用於定義類、結構體或列舉例項的特性。屬性可以進一步分為儲存屬性和計算屬性。儲存屬性用於將常量和變數值儲存為例項,而計算屬性則用於計算值而不是儲存值。

儲存屬性和計算屬性都與例項型別相關聯。當屬性與型別值相關聯時,它被稱為“型別屬性”。儲存屬性和計算屬性通常與特定型別的例項相關聯。但是,屬性也可以與型別本身相關聯。此類屬性稱為型別屬性。

儲存屬性

儲存屬性將常量或變數值儲存為特定類或結構體例項的一部分。它們可以是變數儲存屬性或常量儲存屬性。常量的儲存屬性由“let”關鍵字定義,變數的儲存屬性由“var”關鍵字定義。

在定義儲存屬性期間,允許我們提供“預設值”。此外,在初始化時,我們可以初始化和修改儲存屬性的初始值。

語法

以下是儲存屬性的語法:

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

示例

Swift程式演示結構體中的屬性。

// Structure
struct Number {

   // Stored Property without default value
   var digits: Int
    
   // Stored Property with default value
   let pi = 3.1415
}
// Instance of structure
var n = Number(digits: 12345)

// Assigning a value to the property
n.digits = 67

// Accessing the properties of the structure
print("\(n.digits)")
print("\(n.pi)")

輸出

它將產生以下輸出:

67
3.1415

示例

另一種擁有儲存屬性的方法是擁有常量結構體。因此,結構體的整個例項將被視為“常量的儲存屬性”。

// Structure 
struct Number{

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

// Constant Instance of structure
let n = Number(digits: 12345)

// Accessing the properties of structure
print("\(n.digits)")
print("\(n.numbers)")

/* Structure is a value type so when the instance of 
   the structure is marked as a constant type, then all 
   the properties of that structure is also considered as a constant 
   so we wouldn't be able to change the value of the properties even
   if they are of variable type. But this case doesn't happen in class
   because a class is a 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修飾符。此外,延遲屬性始終是變數型別,因為延遲屬性的初始值可能直到例項的初始化完成之後才能檢索。而常量屬性在初始化之前總是具有值,並且我們不能更改常量屬性的值,因此不允許將其宣告為延遲屬性。

語法

以下是延遲儲存屬性的語法:

class structureName{
   lazy var propertyName = 
}

示例

Swift程式演示類中的延遲屬性。

// Define a class named 'sample'
class Sample {
    
   // Lazy property of type 'number'
   lazy var no = Number()
}

// Define a class named 'number'
class Number {
    
   // Property 
   var name = "Swift"
}

// Create an instance of 'Sample' class
var firstSample = Sample()

// Accessing the lazy property 'no' and then accessing its 'name' property
print(firstSample.no.name)

輸出

它將產生以下輸出:

Swift

例項變數

在Objective C中,儲存屬性還具有例項變數作為備份,用於儲存在儲存屬性中宣告的值。

Swift 4將這兩個概念整合到單個“儲存屬性”宣告中。與其擁有相應的例項變數和備份值,“儲存屬性”包含在一個位置定義的關於變數屬性的所有整合資訊,包括變數名稱、資料型別和記憶體管理功能。

計算屬性

除了儲存屬性外,Swift還支援另一種型別的屬性,即計算屬性。計算屬性不會直接儲存值,而是提供一個getter和一個可選的setter來間接檢索和設定其他屬性和值。其中getter方法在我們要訪問屬性時呼叫,setter方法在我們要修改屬性時呼叫。

要宣告計算屬性,我們必須始終使用var關鍵字以及屬性名稱型別和包含getter和setter的大括號{}。

語法

以下是計算屬性的語法:

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

示例

Swift程式演示類中的計算屬性。

// Class
class sample {

   // Stored properties
   var no1 = 0.0, no2 = 0.0
   var length = 300.0, breadth = 150.0
    
   // Computed properties
   var middle: (Double, Double) {
      get{
         return (length / 2, breadth / 2)
      }
      set(axis){
         no1 = axis.0 - (length / 2)
         no2 = axis.1 - (breadth / 2)
      }
   }
}

// Instance of class 
var result = sample()

// Accessing and initializing properties
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
   
   // Computed property as a read-only property
   var metaInfo: [String:String] {
      return [
         "head": self.head,
         "duration":"\(self.duration)"
      ]
   }
}

// Instance of class
var movie = film()

// Initialzing and accessing properties
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”的預設引數,該引數表示給定屬性的舊值。

示例

// Define class
class Samplepgm {
   var counter: Int = 0{
    
      // WillSwt property observer
      willSet(newTotal){
         print("Total Counter is: \(newTotal)")
      }
        
      // didSet property observer
      didSet{
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

// Instance of class
let NewCounter = Samplepgm()

// Accessing property
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

區域性變數和全域性變數

區域性變數和全域性變數用於計算和觀察屬性。

區域性變數 全域性變數
在函式、方法或閉包上下文中定義的變數。 在函式、方法、閉包或型別上下文之外定義的變數。
用於儲存和檢索值。 用於儲存和檢索值。
儲存屬性用於獲取和設定值。 儲存屬性用於獲取和設定值。
計算屬性也用於此。 計算屬性也用於此。

型別屬性

眾所周知,例項屬性始終屬於特定型別的例項。因此,每當我們建立一個新例項時,它總是包含一組屬性值,並且它們與另一個例項分開。

但是,有時我們希望一個屬性屬於它本身,而不是任何例項。因此,型別屬性解決了這個問題。型別屬性是一個特殊的屬性,它屬於自身,並且只有一個副本,無論建立了多少該型別的例項。儲存型別屬性可以是常量或變數,而計算型別屬性始終是變數。

型別屬性在型別定義部分用大括號{}定義,變數的作用域也在前面定義。對於值型別的型別屬性,使用“static”關鍵字;對於類型別,使用“class”關鍵字。

語法

struct Structname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

enum Enumname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

class Classname {
   class var computedTypeProperty: Int {
      // return an Int value here
   }
}

查詢和設定屬性

與例項屬性一樣,型別屬性也使用“.”語法進行查詢和設定,只是針對型別本身,而不是指向例項。

示例

struct StudMarks {

   // Type properties
   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
         }
      }
   }
}

// Instances of structure
var stud1Mark1 = StudMarks()
var stud1Mark2 = StudMarks()

// Accessing property
stud1Mark1.InternalMarks = 98
print(stud1Mark1.InternalMarks) 

stud1Mark2.InternalMarks = 87
print(stud1Mark2.InternalMarks)

輸出

它將產生以下輸出:

97
87
廣告