您的位置:首页 > 移动开发 > Swift

浅学Swift 3.0.1中的Classes and structures

2017-02-15 10:36 169 查看

序言

类和结构体是那些构建程序代码块的用途广并且灵活的构造器, 你可以通过使用像对常量、变量、和函数完全相同的语法来定义属性和方法, 从而来扩展类和结构体的功能。不像其他编程语言, Swift不要求你为自定义的类和结构体创建单独的声明和实现文件。在Swift中, 你可以定义在同一个文件中定义一个类或结构体, 并且那个类和结构体的额外声明自动对其他代码的使用是可以用的。

注意:类实例在传统上是作为一个对象, 然而,相对其他语言来说, Swift中的类和结构体更接近于函数。

本章目录

类和结构体的比较

定义语法

获取属性

结构体类型的逐一成员构造器

结构体和枚举是值类型

类是引用类型

恒等操作符

在类和结构体之间选择

字符串、数组、字典的赋值和拷贝行为

类和结构体的比较

在swift中, 类和结构体有很多共同之处, 两者都能:

定义存储值的属性

定义提供功能的方法

定义下标来提供获取到它们使用下标语法的值

定义建立初始状态的初始化器

通过扩展,在默认实现外扩展它们的功能

遵循提供某个类的标准功能的协议

还有着结构体没有的能力:

继承使一个类能够继承另一个类的特征

类型转换使你能够在运行时检查和解释一个类实例的类型

析构器使类实例能够释放任何它所分配的资源

引用计数允许对一个类实例的多次引用

注意:结构体是值类型, 所以结构体在代码中传递并且不使用引用计数的时候, 结构体总是被复制。

定义语法

类名和结构体名首字母要大写,形式:

class MyClass {
// 类定义在这儿
}

struct MyStructure {
// 结构体定义在这儿
}

// 这个结构体有两个存储属性
struct Resolution {

var width = 0
var height = 0
}

class VideoMode {
// resolution被初始化成一个新的Resolution结构体实例
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}

// 创建一个结构体实例
let someResolution = Resolution()

// 创建一个类实例
let someVideoMode = VideoMode()


获取属性

你可以使用点语法获取实例属性:

// 通过点语法获取方式:(实例.属性)
someResolution.width = 1
someVideoMode.interlaced = true
somevideoMode.resolution.height = 100


结构体类型的逐一成员构造器

所有结构体都有一个自动生成的逐一成员构造器, 你能使用其来初始化新的结构体实例的成员属性, 新实例的属性的初始化值能通过名字传递给逐一成员构造器。

let newStructureInstance = Resolution(width: 1, height: 2)


和结构体不一样, 类实例没有接收一个默认逐一成员构造器, 也就是说, 类没有默认的逐一成员构造器。

结构体和枚举是值类型

值类型是一个当它被赋值给一个常量或变量, 或传递给函数的时候其值被复制的类型。

在swift中, 所有的基本类型—整型int, 浮点数floating-point, 布尔值Booleans, 字符串strings, 数组arrays和字典dictionaries都是值类型。

在swift中, 所有结构体和枚举都是值类型, 这就意味着任何你创建的结构体和枚举实例–并且任何作为属性的值类型–当在代码中传递时总是被复制。

// valueType是一个Resolution实例
let valueType = Resolution(width: 11, height: 22)

// 变量cinema也是一个Resolution实例
var cinema = valueType


在上面例子中,valueType和cinema有同样的width和height, 但是他们是两个完全不同的实例。

下面给cinema.width赋值:

// 给cinema.width赋值12
cinema.width = 12
// 打印结果:12
print(cinema.width)


然而, cinema的属性width已经改变成12, 但是原来的值依然是11(valueType.width), 也即是说设置cinema.width并不影响存储在valueType中的width。

同样, 也可以用到枚举中:

enum CompassPoint {

case north, south, east, west
}

var currentDirection = CompassPoint.west

let rememberedDirection = currentDirection

currentDirection = .east

if rememberedDirection == .west {
print("rememberedDirection is still .west, has not any changes!")
}

// 打印结果:rememberedDirection is still .west, has not any changes!


类是引用类型

和值类型不一样, 引用类型不能被复制当被赋值给一个常量或变量的时候, 或者当传递给函数的时候。引用类型直接被替换, 不会copy!

let hd = Resolution(width: 111, height: 222)
let tenEightly = VideoMode()

tenEightly.resolution = hd
tenEightly.interlaced = true
tenEightly.name = "1080i"
tenEightly.frameRate = 25.0

let alsoTenEight = tenEightly
alsoTenEight.frameRate = 30.0

// 打印结果:30.0
print(tenEightly.frameRate)


从上面这个例子可以明显地看出, 尽管我们将常量tenEightly赋值给常量alsoTenEight, 当给alsoTenEight的frameRate赋值的时候, tenEightly的frameRate也跟着变了, 这是因为tenEightly和alsoTenEight都是指向同一个VideoMode实例, 所以本质上是对VideoMode实例的改变。

恒等操作符

因为类是引用类型, 所以多个常量和变量在幕后访问/引用同一个类实例是可能的。(结构体和枚举就不行,因为当赋值常量或变量或者传递给函数的时候, 它们总是被拷贝!)

有时, 弄清楚两个常量或变量是否完全引用同一个类实例是有用的。对此, Swift提供了两个恒等操作符:

恒等于(===)

非恒等于(!==)

使用这些操作符来检查两个常量或变量是否访问同一个实例。

class VideoMode {
var frameRate = 0.0
}

let videoModeInstance = VideoMode()
videoModeInstance.frameRate = 12.7

let alsoVideModeInstance = videoModeInstance
alsoVideModeInstance.frameRate = 44.3

if videoModeInstance === alsoVideModeInstance {
print("videoModeInstance and alsoVideoModeInstance refer to the same VideoMode instance")
}


如上面, videoModeInstance和alsoVideoModeInstance可以用恒等式来判断它们是否引用同一个实例。

注意: “===”和“==”是不同的

“===”恒等于意味着类类型的两个常量或变量引用完全一样的类实例

“==”等于意味着两个实例在方面是否相等

在C,C++, OC中, 这些语言使用指针来指向内存中的地址。在swift中, 一个指向某个引用类型实例的常量或变量与C中的指针类似, 但是并不是直接指向内存中的地址的指针并且也不要求你写 “*” 来表明你在创建一个引用, 在swift中, 这些引用被定义像其他常量或变量一样。

在类和结构体之间选择

结构体实例总是通过传递, 类实例总是通过引用传递。

作为一个参考, 当这些条件中有一个或多个被应用到时, 考虑创建结构体:

该结构的主要目的是封装少量相对简单的数据值

当赋值或传递那个结构的实例时,希望被封装的值是被复制而不是引用

该结构存储的任何值本身就是值类型, 这也期望被赋值而不是引用

该结构不需要从另一个存在类型继承属性或行为

好的结构体候选例子包括:

几何形状的大小, 或许要封装一个 width 属性和 height 属性, 两个 Double 类型

一种引用序列范围的方法, 或许要封装一个 start 属性和一个 length 属性, 两个 Int 类型

一个3D坐标系统的点, 或许要封装 x, y和z, 每个类型都是Double

在所有其他情况中, 定义类, 创建那个类的实例通过引用来管理或传递。实际上, 这就意味着大多数自定义数据构造应该是类, 而不是结构体!

字符串、数组、字典的赋值和拷贝行为

在swift中, 像String, Array, Dictionary等很多基本数据类型都是用结构体来实现,这意味着当它们被赋值到一个新的常量或变量的时候, 或者当被传递给一个函数或方法的时候, 他们的值会被拷贝。 这和Foundation不同:NSString, NSArray,和NSDictionary被作为类而不是结构体来实现, 它们总是作为一个存在实例的引用来赋值和传递, 而不是作为拷贝来赋值和传递。

注意:上面是对字符串、数组和字典的描述, 拷贝行为在你的代码中好像总是会发生。然而, swift只有在绝对必要时会执行实际的拷贝。swift会管理所有的值拷贝来确保最优化执行, 你不需要避免赋值来保证性能的最优化。

本文来自Swift3.0.1官方英文版, 作者自译, 欢迎学习, 禁止用于商业用途, 侵权必究! 由于个人能力有限, 欢迎指出其中不足之处!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  类和结构体