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
广告
© . All rights reserved.