类与结构体的共同点:
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义附属脚本用于访问值
- 定义构造器用于生成初始化值
- 通过扩展以增加默认实现的功能
- 实现协议以提供某种标准功能
与结构体相比,类还有如下的附加功能:
- 继承允许一个类继承另一个类的特征
- 类型转换允许在运行时检查和解释一个类实例的类型
- 解构器允许一个类实例释放任何其所被分配的资源
- 引用计数允许对一个类的多次引用
更多信息请参见继承,类型转换,析构过程,和自动引用计数。
注意
- 结构体总是通过被复制的方式在代码中传递,不使用引用计数。
<h3 id = "1">1.值类型与引用类型</h3>
值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。
在之前的章节中,我们已经大量使用了值类型。实际上,在 Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Boolean)、字符串(string)、数组(array)和字典(dictionary),都是值类型,并且在底层都是以结构体的形式所实现。
在 Swift 中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。
“与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝。因此,引用的是已存在的实例本身而不是其拷贝。”
var marray = ["lopl","liu","han"]
func modifyArray() {
var saray = marray
saray.removeAtIndex(2)
}
modifyArray()
marray//并没有变,说明是值拷贝
<h3 id = "2">2.将结构体实例赋值给一个常量,则无法修改结构体中的属性,即使属性是变量。</h3>
struct Cars {
var name = ""
}
let car = Cars()
car.name = "Audi"
//而类则可以修改,因为类是引用类型。
class CreateNewLife{
var name = ""
}
class Animals {
var kind = ""
let planet = "Earth"
lazy var createNewLife = CreateNewLife()
}
let life = CreateNewLife()
let anAnimal = Animals()
anAnimal.kind = "Human"
print(anAnimal,life)
if life === anAnimal {
print("same class")
}else{
print("Different class")
}
print(anAnimal.createNewLife.name)//这时CreateNewLife实例才会被创建
anAnimal.createNewLife.name = "liven"
print(anAnimal.kind,anAnimal.createNewLife.name)
<h3 id = "3">3.结构体和类中的属性定义-getter和setter</h3>
struct Point{
var x = 0.0,y = 0.0
}
struct Size {
var width = 0.0,height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center:Point{//计算属性:即写了get或set的属性。如果只有get,就是只读属性
get{
let centerX = origin.x + size.width/2
let centerY = origin.y + size.height/2
return Point(x: centerX, y: centerY)
}
set(newCenter){
origin.x = newCenter.x - size.width/2
origin.y = newCenter.y - size.height/2
}
}
var arcPoint:Point{//属性观察器didSet,willSet
willSet(newValue){//会将新的值传入
print("will set arcPoint \(newValue)")
}
didSet(oldValue){//会将旧的值传入
//arcPoint = Point(x: 8, y: 9)
print("did set arcPoint \(arcPoint) \(oldValue)")
}
}
static var name = "my rect"//Type property类型属性
//值类型属性一般不能在它自己的实例方法中修改;如果非要修改,需要加关键字mutating
mutating func bigger(x:Double,y:Double) {
size.width += x
size.height += y
}
}
Rect.name
Rect.name = "xxxx"
Rect.name
var rect = Rect(origin: Point(x: 10,y: 10), size: Size(width: 20,height: 30), arcPoint: Point(x: 1, y: 1))
print(rect.arcPoint)
rect.arcPoint = Point(x: 3, y: 4)
print(rect.arcPoint)
var rect2 = rect
rect2.arcPoint = Point(x: 6, y: 6)
print(rect.arcPoint,rect2.arcPoint)
rect.bigger(20, y: 20)
print(rect.size)
class SomeClass {
class var overrideProperty:Int{//get省略了。class关键字表示重写父类的getter实现
return 10
}
}
<h3 id = "4">4.方法</h3>
struct LevelTraker {
static var highestUnlockedLevel = 1
static func unlockLevel(level:Int){
if (level == highestUnlockedLevel + 1) {highestUnlockedLevel = level}
}
static func levelIsUnlocked(level:Int)->Bool{
return level <= highestUnlockedLevel
}
var currentLevel = 1
mutating func advanceLevel(level:Int)->Bool{
if LevelTraker.levelIsUnlocked(level) {
currentLevel = level
return true
}else{
return false
}
}
}
class Player {
var traker = LevelTraker()
var playerName:String
func completeLevel(level:Int) ->Bool{
LevelTraker.unlockLevel(level+1)
if traker.advanceLevel(level+1){
return true
}else{
print("Level \(level) hasn't been unlocked")
return false
}
}
init(name:String){
playerName = name
}
}
var level111 = LevelTraker()
var level121 = LevelTraker()
level121.currentLevel = 2
print(level111.currentLevel, level121.currentLevel)
var player = Player(name:"han")
player.traker.currentLevel
player.completeLevel(1)
player.traker.currentLevel
LevelTraker.highestUnlockedLevel
player.completeLevel(5)
<h3 id = "5">5.构造过程</h3>
class Cars{
var brand:String
var usage:String
//构造函数
init(){
brand = "BMW"
usage = "Family"
}
init(_brand:String,_usage:String){
brand = _brand
usage = _usage
}
}
let audi = Cars(_brand: "Audi", _usage: "Sports")
print(audi.brand,audi.usage)
let car2 = Cars()
print(car2.brand,car2.usage)
<h3 id = "6">6.当属性有默认值,且没有构造方法时,结构体和类拥有默认构造方法。但是结构体可以有带属性参数的默认构造方法(逐一成员构造器),而类没有。</h3>
struct People {
var name:String?
var sex:String?
}
class Books {
var type:String?
var category:String?
var available = true
}
let p = People()
let semdsd = People(name: "han", sex: "famale")
let book = Books()
//var book2 = Books(type:"epub",category:"Computer",available:true)
<h3 id = "7">7.析构过程</h3>
/**
- 析构器只适用于类类型,不能用于结构体。析构器用deinit关键字。
*/
class Telephones {
var type:String?
var category:String?
var available = true
init() {
//
}
deinit{
//析构代码。。。
print("\(type)")
available = false
}
}
/*
析构过程会在ARC回收实例时被系统调用,不需要手动调用。
*/
<h3 id = "8">8.类实例之间的循环强引用</h3>
解决方式:
1.使用weak关键字,弱引用
2.使用unowned,无主引用
<h3 id = "9">9.解决闭包引起的循环引用--定义捕获列表</h3>
protocol SellProducts{
func sellProducts(product:String)
}
class Person {
var name:String
weak var delegate:Seller?
lazy var someClosure:(Int,String)->String = {
//在闭包中将self修饰为无主引用。将delegate 修饰为 弱引用
[unowned self,weak delegate = self.delegate!]//捕获列表
(index:Int,strToProcess:String)->String in
return "\(self.name),\(self.delegate),\(delegate)"
}
init(name:String,delegate:Seller?){
self.name = name;
self.delegate = delegate;
}
func giveSellerProducts(product:String ) -> Bool {
self.delegate?.sellProducts(product)
return true
}
}
class Seller : SellProducts{
var product:String?
func sellProducts( product: String) {
self.product = product
}
}
let seller = Seller()
var person = Person (name: "Hanliu", delegate: seller)
//刚开始seller是没有商品的,要等到Person给seller
print(seller.product)
//person告诉seller,帮我卖苹果
person.giveSellerProducts("apple")
//现在seller手中就有了商品了
print(seller.product!)
person.someClosure(1,"haha")