标签:
与其他编程语言不通,Swift并不要求我们为自定义的类和结构体去创建独立的接口和实现文件。我们所要做的就是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其他代码的外部接口。
小节包含内内容:
类和结构体对比
首先,Swift中类和结构体有很多共同点,共同之处在于(PS:关于属性、方法、下标脚本、构造过程、扩展和协议,其实后面都会说到,教材中提供了书中的具体位置链接):
与结构体相比,类还有如下的附加功能(PS:关于继承、类型转换、析构过程和自动引用计数,都是后面要说的内容):
结构体总是通过被复制的方式在代码中传递,不使用引用计数
类和结构体有着类似的定义方式。通过关键字class和struct来分别表示类和结构体,并在一对大括号内定义他们的具体内容:
class SomeClass {
// 类内部实现
}
struct SomeStructure {
// Structure definition goes here
}
每次定义一个新类,实际上都是定义了一个新的Swift类型,所以命名的时候注意规范,即命名时首字母大写,枚举也是如此。属性和方法名字首字母小写。命名时都要遵循驼峰命名法,并且起名字的时候尽量词能达意。
下面根据具体的例子来说明问题:
// 结构体,描述一个显示器的分辨率
struct Resolution {
var width = 0
var height = 0
}
// 类,描述一个视频显示器的特定模式
class VideoMode {
var resolution = Resolution()
var interfaced = false
var frameRate = 0.0
var name: String?
}
结构体和类都可以通过构造器语法来创建实例进行使用,构造器语法最简单的就是在类或者结构体名称后面添加小括号,构造时属性均会被初始化默认值。如:
// 构造结构体和类的实例
let someResolution = Resolution()
let someVideoMode = VideoMode()
可以通过点语法访问结构体或者类的属性或方法,并且当属性可变,即用var修饰时,可以改变属性值。相比于OC,Swift可以改变结构体或类的属性的子属性的值,而不需要为整个属性赋新值。
// 构造结构体和类的实例
var someResolution = Resolution()
let someVideoMode = VideoMode()
// 点语法访问属性并修改值
someResolution.height = 200
someVideoMode.frameRate = 12.12
someVideoMode.resolution.width = 300
注意,所有的结构体都有一个自动生成的成员逐一构造器,就是建立的时候为每个属性赋值。然而类并没有这个特性。只需在构造时输入左括号,自然会有提示。
结构体和枚举是值类型
值类型赋值给一个变量、常量或者被传递给一个函数时,其值会被拷贝,新拷贝的值和原来的值是完全隔离的,即他们的改变是独立的。在Swift中,整数、浮点数、布尔值、字符串、数组和字典,都是值类型,并且在底层都是以结构体的形式所实现。显然,结构体和枚举类型都是值类型。下面简单地代码很能说明问题:
// 值传递,对象以及所有属性都发生了拷贝
let someResolution = Resolution(width: 1920, height: 1080)
var anotherResolution = someResolution
anotherResolution.width = 2880
anotherResolution.height = 1600
// 通过输出结果,可以清晰体会到值传递是复制了另外一份数据
print(someResolution.height,someResolution.width) // 1080 1920
print(anotherResolution.height, anotherResolution.width) // 1600 2880
类是引用类型
与值类型不同,引用类型再被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝,因此引用是引的已存在的示例本身而不是拷贝。可以理解为多个指针指向同一个内存区域,任何一个指针对数据进行操作时,其他指针取到数据也是已经被修改的数据。如:
// 类是引用类型
let someVideoMode = VideoMode()
someVideoMode.frameRate = 2.05
someVideoMode.resolution.height = 300
let anotherVideoMode = someVideoMode
anotherVideoMode.frameRate = 99.99
anotherVideoMode.resolution.height = 2222
// 展示现在两个类属性的值
someVideoMode.frameRate // 99.9999
someVideoMode.resolution.height // 2222
anotherVideoMode.frameRate // 99.999
anotherVideoMode.resolution.height // 2222
观察上面代码会看到一个比较迷惑的地方,那就是已经使用 let 设置类实例,为什么还能修改它的值呢?如果结构体使用 let 修饰,是无法更改里面的值的。为什么呢?为什么呢??原因很简单,因为类是引用类型,也就是说 someVideoMode 和 anotherVideoMode 本身并没有存储值,改变的仅仅是被引用的属性的值,他们本身的值并没有改变,所以可以用 let 修饰为常量来使用。
因为类是引用类型,有可能多个常量和变量幕后同时引用一个类实例。如果能够判断两个常量或者变量是否引用同一个类实例,将会很有帮助。为了达到这种目的,Swift内建了两个恒等运算符:
注意,”等价于“(用三个等号表示 ===) 与 等于(用两个等号表示 ==)的不同:
类和结构体的选择
当考虑使用结构体合适使用类的时候,如果能用结构体,就果断使用结构体吧,尽量少的使用类。我在看atSwift第一届Swift开发者大会的时候,有好几个演讲人员都强调了这一点,能用结构体就不用类。在教材中,也是提供了什么情况下使用结构体效果更好。
按照通用的准则,当符合一条或多条以下条件时,请考虑使用结构体:
举例来说,一下情境中适合使用结构体:
教程中的话:在所有其他案例中,定义一个类,生成它的实例,并通过引用来管理和传递。实际上,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。
其实,当教材和现实有了点冲突,我选择相信多用结构体。。。
关于Swift中的值传递和OC中的常用数据类型
在Swift中,所有值传递都是以拷贝的形式发生的,他们的低层都是由结构体实现的。这点和和OC中是不一样的。在Object-C中,NSString、NArray和NSDictionary中低层均以类的形式实现,它们在被赋值或者被传入参数时,不会发生值拷贝,而是传递现有实例的引用。
注意,以上对字符串、数组、字典的“拷贝”行为的描述,在代码中,好像拷贝行为看起来总会发生。然而,Swift在幕后只在绝对必要时才执行实际的拷贝。Swift管理所有值拷贝以确保性能最优化,所以没必要去回避赋值来保证性能最优化。
为啥现在写的这么慢了呢?是因为工作忙了么,毛线,就是过了新鲜劲,懒了。。。。。吾日三省吾身,早上吃什么,中午吃什么,晚上吃什么,就是忘了自省下为啥今天没坚持写点东西~
昨天晚上把权利的游戏第六季的前三集一次性看完了,也是过瘾,红巫女威武,囧哥威武!另外,感觉这张图的尺度好大~滑稽.jpg
另外,点击查看前几篇文章
Swift-类和结构体(Class and Structures)(八)
标签:
原文地址:http://blog.csdn.net/xxh0307/article/details/51360773