iOS Swift No.9 - 结构体与类

第九章 结构体与类

结构体和类其实是一个用通用且灵活的方法来构造代码块的东西。而我们可以用定义常量,变量或函数的方法来定义结构体和类的属性方法,以此来扩展该结构体或类的功能。通常很官方的理解还不如翻译成自己的白话文容易理解很概念性的东西。

1. Comparing Structures and Classes (结构体和类的对比)

结构体和类的相同点:

  1. 定义属性用于存储值
    define properties to store values
  2. 定义方法用于提供功能
    define methods to provide functionality
  3. 定义下标操作使得可以通过下标语法来访问实例所包含的值
    define subscripts to provide access to their values using subscript syntax
  4. 定义初始化用于生成初始化值
    define initialisers to set up their initial state
  5. 通过扩展以增加默认实现的功能
    be extended to expand their functionality beyond a default implementation
  6. 实现协议以提供某种标准功能
    conform to protocols to provide standard functionality of a certain kind

相比结构体,类有下面这些额外的优势:

  1. 继承 :允许一个类继承另一个类的特征
    Inheritance enables one class to inherit the characteristics of another
  2. 类型转换允许在运行时检查和解释一个类实例的类型
    Type casting enables you to check and interpret the type of a class instance at runtime.
  3. 析构器允许一个类实例释放任何其所被分配的资源
    Deinitializers enable an instance of a class to free up any resources it has assigned.
  4. 引用计数允许对一个类的多次引用
    Reference counting allows more than one reference to a class instance.

1.1 定义结构体和类的语法

定义结构体(structure)和类(class)的方法其实是比较相似的。用structclass关键字分别引出介绍该结构体和类。结构体和类的定义内容需要放在大括号内

struct SomeStructure {
    // 这里是结构体的定义
    // 结构体的名称(SomeStructure)要大些
}
class SomeClass {
    // 这里是类的定义
}

不管什么时候定义结构体或者类的时候都要用大写结构体或类的名称,命名结构体或类时等于说创建了一个新的swift 类型,用大写的原因是因为我们要匹配swift 类型(String Bool …)的命名规则,而在定义属性或方法的时候要用小写。注意区分。。。

下面是一个定义结构体和类的实例,从该例子中可以隐约看到结构体和类的共同点和不同点

struct Resolution {
    var width = 0
    var height = 0
}
class VideoMode {
    var resolution = Resolution()
    var interlaced = false
    var frameRate = 0.0
    var name: String?
}

VideoMode类里面有一个变量属性的引用 var resolution = Resolution()其实这种写法(大写字母后面跟个括号 一般情况下都是引用结构体,函数等)。该引用说明了 VideoMode类的一个属性它要继承来自另一个结构体里面的属性,所以类比结构体多一个特性就是 类它可以继承结构体或另一个类里面的特性。

1.2 结构体和类的实例

上面案例里的分辨率(Resolution)结构体和视频模式(VideoMode)类的定义仅仅只是描述了什么是结构体和类或者该结构体或类由哪些东西组成。而并没有具体描述分辨率是多少,视频模式有哪几种。所以在这个时候我们就需要创建一个实例来具体描述分辨率和视频模式。

// 实例化结构体和类的写法比较相似
let someResolution = Resolution()
let someVideoMode = VideoMode()

利用初始化语法来创建一个新的实例用此来获取初始值。初始化语法的依法一般是在结构体或类的名字后面添加一个空白的小括号。就像Resolution()VideoMode()

1.3 Accessing Properties (读取属性)

可以用dot语法来读取实例的某一个属性,可以在实例名称后面加上想要读区的属性,在用.开隔开实例名和属性名 中间没用空格。

print("The width of someResolution is \(someResolution.width)")
// 输出:The width of someResolution is 0

同样也可以用dot语法来分配一个新值给变量属性

print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// 输出:The width of someVideoMode is 0

1.4 Memberwise Initializers for Structure Types

Swift的结构体支持成员逐一初始化器操作。也就是说可以用初始化结构体实例的成员,结构体初始值会由这个成员逐一初始化器会通过实例的名称将初始化的值传递到结构体的属性里面

let vga = Resolution(width: 640, height: 480)

上面是结构体的实例,成员逐一初始化会将640,480通过结构体的名称(Resolution)传递并初始化这两个值给结构体的属性。

2. Structure and Enumeration are value type.

swift语言里面什么是值类型呢?结构体和枚举的值类型其实是一个可以通过传递和赋值起所在的结构体或枚举里面的属性值 。

let hd = Resolution(width: 1920, height: 1080)
var cinema = hd 
cinema.width = 2048

上面的例子中Resolution(width: 1920, height: 1080)就是常量hd的一个值。变量cinema则引用了hd。也可以用dot语法来读取cinema的宽度(cinema.width) 并且重新给其分配一个值(2048)。

print("cinema is now \(cinema.width) pixels wide")
// 输出:cinema is now 2048 pixels wide
print("hd is still \(hd.width) pixels wide")
// 输出:hd is still 1920 pixels wide

在这里插入图片描述
重新分配后的cinema宽度将会改变为2048,而hd的宽度则不会变,是因为变量cinema是引用了hd的属性,从而使实例cinema也会继承hd所拥有的属性 也就是继承hd后cinema属性是width: 1920 height: 1080,不同的是继承后的hd和cinema它们的属性都是各自独有且相同的,改变cinema的属性并不会改变hd的属性。这个例子是对结构体和类的实例属性进行的操作。即结构体或类的属性可以进行引用或继承,引用或继承实例化后结构体或类的属性后,改变引用后的结构体或类的属性从而会复制或创建一个新的属性。不会对原结构体或类的属性做同步改变。原结构体或类的属性不变。

enum CompassPoint {
    case north, south, east, west
    // mutating: 变形,突变
    mutating func turnNorth() {
        self = .north
    }
}

mutating 关键字用于修改结构体,类,枚举中的变量。

var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection.turnNorth()
print("The current direction is \(currentDirection)")
// 输出:The current direction is north
print("The remembered direction is \(rememberedDirection)")
// 输出:The remembered direction is west 

现在的变量currentDirection它的值是枚举的一个成员west。创建一个新的常量叫rememberDirection它的值引用了currentDirection的值 也就是west,currentDirection.turnNorth() - 用dot语法读取可以读取结构体,类和枚举的属性,属性不一定是常量,变量也有可能是一个变形的函数。该函数turnNorth()就有一个属性且该属性的值就是north。Line3重新分配值的时候currentDirect就会引用函数里面的属性。

3. Classes Are Reference Types (类是引用类型)

结构体和枚举可以被用作值类型 而类确实引用类型,实例化后的类,它的变量或常量被床底给某个函数的时候,值是不会被复制的,下面这个例子可以举例说明。

// 实例化VideoMode类
let tenEighty = VideoMode()
// 属性
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
/* 类的实例再引用 会创建一个新的实例 
   和结构体枚举不同的是
   类实例的再引用 创建新的实例会指代同一个类的属性
*/ 
let alsoTenEighty = tenEighty
// 重新分配frameRate一个值
alsoTenEighty.frameRate = 30.0

在这里插入图片描述

3.1 Identity Operators (恒等运算符)

因为类是一个引用类型,有时候我们创建的类的实例会被多个变量或常量所引用。再去创建一个新的实例,而新的实例有引用同一个类的属性,类的引用就是引用类的属性。它不会像结构体或枚举那样,创建一个新的实例并复制一个新的属性。

结构体和枚举是值类型,再创建一个新的实例引用原结构体或枚举的实例时,也会创建一个新的实例同样也会复制原结构体或枚举的属性。恒等运算符或非恒等运算符是用来检查,两个常量或变量会不会引用同一个类的实例。

恒等运算符 ( === )
非恒等运算符 ( !== )

// 用if条件语句判断两个实例的属性是否相等
if tenEighty === alsoTenEighty {
    print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
发布了12 篇原创文章 · 获赞 71 · 访问量 1293

猜你喜欢

转载自blog.csdn.net/weixin_45026183/article/details/105039471