swift简单总结(十九)—— 类和结构体

版本记录

版本号 时间
V1.0 2017.07.28

前言

  我是swift2.0的时候开始接触的,记得那时候还不是很稳定,公司的项目也都是用oc做的,并不对swift很重视,我自己学了一段时间,到现在swift3.0+已经出来了,自己平时也不写,忘记的也差不多了,正好项目这段时间已经上线了,不是很忙,我就可以每天总结一点了,希望对自己对大家有所帮助。在总结的时候我会对比oc进行说明,有代码的我会给出相关比对代码。
1. swift简单总结(一)—— 数据简单值和类型转换
2. swift简单总结(二)—— 简单值和控制流
3. swift简单总结(三)—— 循环控制和函数
4. swift简单总结(四)—— 函数和类
5. swift简单总结(五)—— 枚举和结构体
6. swift简单总结(六)—— 协议扩展与泛型
7. swift简单总结(七)—— 数据类型
8. swift简单总结(八)—— 别名、布尔值与元组
9. swift简单总结(九)—— 可选值和断言
10. swift简单总结(十)—— 运算符
11. swift简单总结(十一)—— 字符串和字符
12. swift简单总结(十二)—— 集合类型之数组
13. swift简单总结(十三)—— 集合类型之字典
14. swift简单总结(十四)—— 控制流
15. swift简单总结(十五)—— 控制转移语句
16. swift简单总结(十六)—— 函数
17. swift简单总结(十七)—— 闭包(Closures)
18. swift简单总结(十八)—— 枚举

类和结构体

  类和结构体是人们构建代码所用的一种通用且灵活的构造体。与其他编程语言不同的是,swift并不要求你为自定义类和结构体去创建独立的接口和实现文件,你需要做的就是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其他代码的外部接口。

下面将从下面几个方向进行讲述

  • 类和结构体对比
  • 结构体和枚举是值类型
  • 类是引用类型
  • 类和结构体的选择
  • 集合collection类型的赋值和复制行为

类和结构体对比

1. 类和结构体的对比

swift中类和结构体有很多共同点,主要是:

  • 定义属性用于存储值
  • 定义方法用于提供功能
  • 定义附属脚本用于访问值
  • 定义构造器用于生成初始化值
  • 通过扩展以增加默认实现的功能
  • 符合协议以对某类提供标准功能

与结构体相比,类还有如下的功能:

  • 继承允许一个类继承另一个类的特征
  • 类型转换允许在运行时检查和解释一个类实例的类型
  • 解构器允许一个类实例释放任何其所被分配的资源
  • 引用计数允许对一个类的多次引用

注意:结构体总是通过被复制的方式在代码中传递,因此,请不要使用引用计数。

2. 定义

  下面我们看一下类和结构体是如何定义的,习惯上类名和结构体名是以大写字母开头,属性和方法是以小写字母开头,这复合swift的习惯。

下面看一下具体的定义。


class SomeClass {
    //class definition goes here
}

struct SomeStruct {
    //structure definition goes here
}

下面我们接着看定义实例。

struct Resolution {
    var width = 0
    var height = 0
}

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

3. 类和结构体实例

  可以用下边方式进行实例化,结构体和类都使用构造器语法来生成新的实例,构造器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括号。

let someResolution = Resolution()
let someVideoMode = VideoMode()

4. 属性访问

  可以使用点语法,你可以访问实例中所包含的属性,语法规则是:实例名称紧跟属性名。

    let someResolution = Resolution()
    let someVideoMode = VideoMode()
    print(someResolution.width)
    print(someVideoMode.resolution.width)

你可以使用点语法为属性变量赋值。

someVideoMode.resolution.width = 100

  大家可以看点,swift允许使用点语法直接给一个属性赋值,这个比OC要灵活的多了,大家估计还记得OCframe,不可以直接改变其中的成员,要找一个中间变量,改变中间变量的成员,修改以后在赋值回去才可以。这一点swift要灵活的多了。

5. 结构体类型的成员逐一构造器 - Memberwise Initializers for structure Types

  所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性,新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器中,下面看代码。

let resolution = Resolution(width: 1920, height: 1080)

与结构体不同,类实例没有默认的成员逐一构造器。


结构体和枚举是值类型

  值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是其的拷贝。其实,在swift中,所有基本类型:整数、浮点数、布尔值、字符值、数组和字典,都是值类型,并且都是以结构体的形式在后台所实现。在swift中,所有的结构体和枚举都是值类型,这意味着他们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。

let resolution = Resolution(width: 1920, height: 1080)
var cinema = resolution

  在上面的例子中,声明一个常量resolution并给一个初始值,然后又定义了名字为cinema的变量,其值为之前声明的resolution,因为Resolution是一个结构体,所以cinema的值其实是resolution的一个拷贝副本,而不是resolution本身,尽管resolutioncinema有着相同的宽和高,但是在后台中,它们是两个完全不同的实例。

下面看这个例子

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let resolution = Resolution(width: 1920, height: 1080)
        var cinema = resolution
        cinema.width = 2080
        print("cinema = \(cinema)")
        print("resolution = \(resolution)")
    }
}

下面看输出结果

cinema = Resolution(width: 2080, height: 1080)
resolution = Resolution(width: 1920, height: 1080)

  进一步证明了结构体是值类型,在将resolution赋值给cinema的时候,实际上是将resolution中所存储的值进行拷贝,然后将拷贝的数据存储到新的cinema中,结果是两个完全独立的实例碰巧包含有相同的数值。修改其中一个的值,不会影响另外一个的值。

枚举也遵循相同的准则

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        var currentDirection = CompassPort.West
        let lastDirection = currentDirection
        currentDirection = .East
        if lastDirection == .West {
            print("The remember direction is still .West")
        }
        else {
            print("The remember direction is still .East")
        }
    }
}

下面看输出结果

The remember direction is still .West

说明枚举也是值类型。


类是引用类型

  与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,操作的是引用,并不是拷贝,因此,引用的是已知存在的实例本身而不是拷贝。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let resolution = Resolution()
        let mode = VideoMode()
        mode.resolution = resolution
        mode.interlaced = false
        mode.name = "10086"
        mode.frameRate = 25.0
        
        let nextMode = mode
        nextMode.frameRate = 30.0
        print(mode.frameRate)
        print(nextMode.frameRate)
    }
}

下面看输出结果

30.0
30.0

  可见,类是引用类型。还需要注意的是modenextMode被声明为常量,而不是变量,然而你依然可以更改里面的frameRate,因为这两个常量本身不会改变,它们并不存储这个nextMode实例,在后台仅仅是对nextMode的引用,所以,改变的是被引用的基础nextModeframeRate参数,而不改变常量的值。

1. 恒等运算符

  因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例,如果能够判断两个常量或者变量是否引用同一个类实例将会很有帮助,为了这个目的,swift内建了两个恒等运算。

  • 等价于(===)
  • 不等价于(!==)

看下面这个例子。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let resolution = Resolution()
        let mode = VideoMode()
        mode.resolution = resolution
        mode.interlaced = false
        mode.name = "10086"
        mode.frameRate = 25.0
        
        let nextMode = mode
        nextMode.frameRate = 30.0
        print(mode.frameRate)
        print(nextMode.frameRate)
        
        if mode === nextMode {
            print("They are the same instance !")
        }
        else {
            print("They are not the same instance !")
        }
    }
}

下面看输出结果

30.0
30.0
They are the same instance !

这里还要注意=====的不同:

  • ===表示两个类类型的常量或者变量是否引用同一个类实例。
  • ==表示两个实例的值相等或者相同。

2. 指针

  对于COC,你知道使用指针来引用内存中的地址,一个swift常量或者变量引用一个引用类型的实例与C语言中的指针类似,不同的是并不直接指向内存中的某个地址,而且也不要求你使用星号*来表明你在创见意一个引用,swift中这些引用于其他的常量或者变量的定义方式相同。


类和结构体的选择

  在选择之前要记住,结构体是值类型,类是引用类型,按照通用标准,当符合下面的条件时,请考虑结构体。

  • 结构体的主要目的是用来封装少量相关简单数据值。
  • 有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用。
  • 任何在结构体中存储的值类型属性,也将会被拷贝,而不是被引用。
  • 结构体不需要去继承另一个已存在类型的属性或者行为。

简单举几个适合结构体的例子。

  • 几何形状的大小
  • 一定范围内的路径
  • 三维坐标系内一点

在所有其他案例汇中,基本都是定义一个类,生成一个它的实例。


集合类型的赋值和拷贝行为

  swift中的字符串String、数组Array和字典Dictionary类型均以结构体的形式实现,这意味着,StringArrayDictionary类型的数据被赋值给新的变量或者常量,或者被传入函数方法中,它们的值会发生拷贝行为(值传递方式)。

  而在OC中字符串NSString、数组NSArray和字典NSDictionary类型均以类的形式出现,这与swift中以值传递的方式是不同的,字符串NSString、数组NSArray和字典NSDictionary在发生赋值或者传入函数方法中时,不会发生值拷贝,而是传递已存在实例的引用。

注意:实际上,在你的代码中,数组字典字符串的拷贝好像确实是在有拷贝行为的地方产生过,然而,在swift后台中,只有确有必要,actural实际拷贝才会被执行,swift管理拷贝以确保最优化的性能,所以你也没有必要去避免赋值以保证最优性能,实际赋值由系统管理优化。

后记

未完,待续~~~

秦时明月
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容