Swift类和结构体

与其他编程语言不同,Swift并不要求你为自定义的类和结构体去创建独立的接口和实现文件。你所要做的是再一个单一的文件中定义一个类或者结构体,系统将会自动生成面向其他代码的外部接口。
类和结构体的对比
共同点:
定义属性用于存储值
定义方法用于提供功能
定义下标用于通过下标语法访问值
定义初始化器用于初始化值
通过扩展以增加实现的功能
符合协议对某类提供标准的功能
类还具有下面附加功能
继承
类型转换允许在运行时检查和解释一个类实力的类型
取消初始化器允许一个类实力释放任何其所被分配的资源
引用计数允许对一个类的多次引用

注意:结构体总是以复制的方式在代码中传递,因此请不要使用引用计数
class testClass{
var interlaced = false
}
struct testStruct{
var width = 100
var height = 50

}
生成结构体
let structExample = testStruct()//初始化器
生成类实例
let classExample = testClass ()//初始化器

与OC不同的是Swift允许直接设置结构体属性的子属性

结构体成员逐一初始化器
let structExample   =   testStruct( width:640, heigth: 480 )
与结构体不同的是类没有逐一初始化器
结构体和枚举是值类型
将值类型赋给一个变量,常量或者作为参数是,实际上操作的是其拷贝
所有的基本类型都是值类型,并且都是以结构体的形式在后台所实现
类是引用类型
与值类型不同,引用类型在被赋予到一个变量,常量或者被传递到一个函数时,操作的并 不是其拷贝。因此,引用的是已存在的实例本身而不是其拷贝
恒等运算符
等价于 ===
不等价于!==

===与==(等于)的不同:
等价于表示两个类类型的常量或者变量引用同一个类实例
等于表示两个实例的值相等或相同
在自定义类和结构体时有义务决定两个实例相等的标准

指针
一个Swift常量或者变量引用一个引用类型的实例与C语言的指针类似,不同的是不直接指向内存中的某个地址,也不需要*。这些引用与其他常量或变量的定义相同

使用类还是结构体?
当符合下面一条或者多条的时候也考虑使用结构体:
结构体的主要目的是用来封装少量相关简单的数据值
结构体在赋值或传递时,封装的数据将会被拷贝而不是被引用
任何存储在结构体中的类型属性,也将会被拷贝二不是引用
不需要继承
合适结构体的候选者:
几何形状的大小
一定范围内的路径
三维坐标系内的一点
集合类型的赋值和拷贝
数组和字典类型均以结构体的形式出现,数组拷贝行为与字典和其他结构体有些不同。
NSArray和NSDictionary实例总是以对已有实例引用,二不是拷贝的方式赋值和传递
在你的代码·中·是在有拷贝行为的地方产生过,在Swift的后台中,只有确有必要才会拷贝。Swift自动管理拷贝确保性能最优

字典类型的赋值和拷贝行为
如果字典实例中所储存的键(keys)和/或值(values)是值类型(结构体或枚举),当赋值或调用 发生时,它们都会被拷贝。相反,如果键(keys)和/或值(values)是引用类型,被拷贝的将 会是引用,而不是被它们引用的类实例或函数。字典的键和值的拷贝行为与结构体所储存 的属性的拷贝行为相同。
数组类型的赋值和拷贝行为
当操作数组内容时,数组(Array)能?供接近 C 语言的的性能,并且拷贝行为只有在必要时 才会发生
如果你将一个数组(Array)实例赋给一个变量或常量,或者将其作为参数传递给函数或方法 调用,在事件发生时数组的内容不会被拷贝。相反,数组公用相同的元素序列。当你在一 个数组内修改?一元素,修改结果也会在另一数组显示。
对数组来说拷贝行为只发生在数组长度发生改变时
只有当数组拷贝确要发生时,数组内容的行为规则与字典中键值的相同
//没有改变长度的情况
var a = [1,2,3]
var b = a
var c = a

a[0] = 0
b[0] = 0
c [0] = 0

//改变长度的情况
a.append(4)//发生拷贝
a[0] = 99
b[0] = 0
c [0] = 0

a[0] = 99
b[0] = 0
c [0] = 0

确保数组的唯一性
在操作一个数组时,或将其传递给函数以及方法调用之前是很有必要确定数组是唯一拷贝的。通过在数组变量上调用unshare方法来确定数组引用的唯一性(当数组赋给一个常量的时候,不能调用unshare方法
如果一个数组有多个变量引用,在其中的一个变量上调用unshare方法,则会拷贝此数组,此时这个变量将会有属于他自己的独立拷贝。当数组仅仅被一个变量引用时,则不会有拷贝发生
b.unshare()
b[0] = 105
a[0] = 99
b[0] = 105
c[0] = 0

判断那两个数组是否公用相同的元素
通过恒等===和!==来判断两个数组是否公用相同的存储空间和元素
if(a == b){}
if(a[0...1]===b[0...1]){}

强制赋值数组
通过copy方法强制显性复制
这个方法对数组进行了浅拷贝(shallow copy)并且返回包含此拷贝的新数组
var names = ['a','b']
var copyName = names.copy
copyName[0] = 'c'
names[0] = 'a'

计算属性可以用于类,结构体和枚举,存储属性只用于类和结构体。
存储属性和计算属性通常用于特定类型的实例。但是属性也可以直接用于类型本身,这种属性成为类型属性
可以定义属性监视器来监控属性值的变化,一触发一个自定义的操作。属性监视器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上

存储属性
存储属性就是存储在特定类或结构体的实例李德常量或者变量,存储属性可以是变量存储属性也可以常量存储属性
把一个结构体赋值给一个常量后就不能修改他的值,因为结构体是值类型的
把一个类赋值给一个常量后能修改他的值,因为类是引用类型的
延迟存储属性
延迟存储属性是指在第一次调用的时候才会计算其初始值的属性。在属性前使用@lazy来标志一个延迟存储属性
注意:必须将延迟存储属性声明成变量(使用 var 关键字) ,因为属性的值在实例构造完成 之前可能无法得到。 而常量属性在构造过程完成之前必须要有初始值, 因此无法声明成延迟 属性
当属性的值依赖于在实例的构造过程结束前无法知道具体的值的外部因素时,或者当属性值需要复杂或者大量计算时,可以只在需要的时候来计算他
存储属性和实例变量
Swift中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这避免了不同场景下访问方式的困扰,同时也将属性的定义化。
一个类型中属性的全部信息——包括命名、类型和内存管理特征—— 都在唯一一个地方(类型定义中)定义。
计算属性
计算属性不存储值,而是提供一个getter来获取值,一个可选的setter来间接设置其他属性或变量的值
struct Point{}
struct Size{}
struct Rect{

var center:Point{
get{

return //Point类型
}

set(prama){
origin.x = newCenter.x - (size.width / 2)
18. origin.y = newCenter.y - (size.height / 2)
}
}
}

setter的便捷声明
set{
origin.x = newValue.x - (size.width / 2)
}

只读计算属性
只有 getter 没有 setter 的计算属性就是只读计算属性。 只读计算属性总是返回一个值, 可 以通过点运算符访问,但不能设置新的值。
注意:必须使用 var 关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。 let 关键字只用来声明常量属性,表示初始化后再也无法修改的值。
只读计算属性的声明可以去掉 get 关键字和花括号:
struct Rect{

var center:Point{
//去掉画括号和关键字get
return //Point类型
}
属性监视器
 每次属性被设置值的时候都会调用属性监视器。  甚至 新的值和现在的值相同的时候也不例外
可以为 除了延迟存储属性之外的其他存储属性添加属性监视器, 也可以通过重载属性的方式 为继承的属性(包括存储属性和计算属性)添加属性监视器。
不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响
应值的变化。
可以为属性添加如下的一个或全部监视器:
willSet 在设置新的值之前调用
didSet 在新的值被设置之后立即调用
willSet 监视器会将新的属性值作为固定参数传入,在 willSet 的实现代码中可以为这个参数 指定一个名称,如果不指定则参数仍然可用,这时使用默认名称 newValue 表示。
 didSet 监视器会将旧的属性值作为参数传入, 可以为该参数命名或者使用默认参数
名 oldValue。
class StepCounter {
 var totalSteps: Int = 0 {
 willSet(newTotalSteps) {
 println("About to set totalSteps to \(newTotalSteps)")
 }
 didSet {
 if totalSteps > oldValue {
 println("Added \(totalSteps - oldValue) steps")
 }
 }
 }
 }
注意:如果在 didSet 监视器里为属性赋值,这个值会替换监视器之前设置的值。
计算属性和属性监视器所?述的模式也可以用于全局变量和局部变量
在全局或局部范围都可以定义计算型变量和为存储型变量定义监视器, 计算型变量跟
计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
注意:全局的常量或变量都是延迟计算的,跟延迟存储属性相似,不同的地方在于,全局的 常量或变量不需要标记@lazy 特性;局部范围的常量或变量不会延迟计算。
对于值类型(结构体和枚举)可以定义存储型和计算型属性,对于类则只能定义计算型属性
类型属性用于定义特定类型所有实例共享的数据。
值类型的存储型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性

类型属性作为类型定义的一部分写在类型最外层的{}中。
使用static来定义值类型的类型属性,关键字class来为类定义类型属性。
类型属性是通过类型本身来获取和设置的,而不是通过实例


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值