10 Swift 析构方法\内存管理\可选类型

1. 析构方法

析构方法

对象的内存被回收前夕被隐式调用的方法,对应OC中的dealloc方法
主要执行一些额外操作,例如释放一些持有资源,关闭文件,断开网络

class FileHandler {

    var fd: Int32? // 文件描述

    // 指定构造器
        init(path: String){

        // 需要打开的文件路径,打开方式(只读)
        // open方法是UNIX的方法
        let ret = open(path, O_RDONLY)
    
        if ret == -1 {
    
            fd = nil
        }else{
    
            fd = ret
        }
    
        print("对象被创建")

    }    
    // 析构方法
    deinit{
    // 关闭文件
        if let ofd = fd{
    
            close(ofd)
        }
        print("对象被销毁")
    }
}

var fh: FileHandler? = FileHandler(path:     "/Users/gapjun/Desktop/nicai.png")

析构方法的自动继承

父类的析构方法会被自动调用,不需要子类管理

class Person {

    var name: String

    init (name: String){
    
        self.name = name
    
        print("Person init")
    }

    deinit{

        print("Person deinit")
    }

}

class SuperMan: Person {

    var age: Int

    init(age: Int){
    
        self.age = age
    
        super.init(name: "nicaio")
    
        print("SuperMan init")
    }

    deinit{

        // 如果父类的析构方法不会被自动调用,那么我们还需要关心父类,但是如果这样做子类是比较痛苦的
    
        print("SuperMan deinit")
    }

}

var sm: SuperMan? = SuperMan(age: 30)

sm = nil 

2. 内存管理

Swift内存管理
管理引用类型的内存,不会管理值类型,值类型不需要管理
内存管理原则: 当没有任何强引用指向对象,系统会自动销毁对象
默认 情况下所有的引用都是强引用
如果做到该原则: ARC

class Person {

    var name: String

    init(name: String){

    self.name = name
    }

    deinit{
        print("deinit")
    }
}

var p: Person? = Person(name: "nicia")

p = nil

weak弱引用

class Person1 {

    var name: String

    init(name: String){

        self.name = name
    }

    deinit{
        print("deinit")
    }
}

// 强引用,引用计数 +1
var strongP = Person1(name: "TMD") // 1

var strongP2 = strongP  // 2

/*
    弱引用, 引用计数不变
    如果利用weak修饰变量,当对象释放后会自动将变量设置为nil
    所以利用weak修饰的变量必定是一个可选类型,因为只有可选类型才能设置为nil
*/

weak var weakP: Person1? = Person1(name: "WOCAO")

if let p = weakP{

    print(p)
}else{
    print(weakP)
}

unowned: 无主引用,相当于OC unsafe_unretained

unowned与weak的区别
1、利用unowned修饰的变量,对象释放后不会设置为nil,不安全
利用weak修饰的变量,对象释放后会设置为nil
2、利用unowned修饰的变量,不是可选类型
利用weak修饰的变量,是可选类型

class Person2 {

    var name: String

    init(name: String){

        self.name = name
    }
    deinit{

        print("deinit")
    }
}

unowned var weakP2: Person2 = Person2(name:     "gaojun")

循环引用

ARC不是万能的,它可以的解决内存问题,但是在某些场合不能很好的解决内存泄露问题
例如两个或者多个对象之间的循环引用问题


class Person3 {

    let name: String // 姓名

    // 人不一定有公寓,如果这里不加weak的话,当对象并没有销毁
    weak var apartment: Apartment? // 公寓

    init(name: String){

        self.name = name
    }
    deinit{

        print("\(self.name) deinit")
    }
}

class Apartment {
    
    let number: Int // 房间号

    var tenant: Person3? // 租客

    init(number: Int){

        self.number = number
    }
    deinit{

        print("\(self.number) deinit")
    }

}

var p3: Person3? = Person3(name: "wokao")

var a: Apartment? = Apartment(number: 888)

p3!.apartment = a // 人有一套公寓

a!.tenant = p3! // 公寓中住着一个人

p3 = nil

a = nil

class Person4 {

    let name: String // 姓名

    // 人不一定有信用卡
    var card: CreditCard?

    init(name: String){

        self.name = name
    }
    deinit{

        print("\(self.name) deinit")
    }
}

class CreditCard {

    let number: Int

    // 信用卡必须有所属用户,当某一个变量/常量必须有值,一直有值,那么可以使用unowned修饰
    unowned let person: Person4

    init(number: Int, person: Person4){

        self.number = number
        self.person = person
    }
    deinit{

        print("\(self.number) deinit")
    }
}

var p4: Person4? = Person4(name: "nima")

var cc: CreditCard? = CreditCard(number: 88888, person: p4!)

p4 = nil

cc = nil

3. 可选类型

可选类型:

可选类型的本质其实就是一个枚举
None没有值
Some有值
格式: Optional<类型> 或者在类型后面加上一个问号
由于可选类型在Swift中随处可见,所以系统做一个语法糖,在类型后面加上?

var opa: Optional<Int>

var opb: Int?

var nora: Int

nora = 10

print(nora)

print(opb)

/*
    基本类型变量,在使用之前必须进行初始化,否则报错
    目的: 安全,不管在什么时候访问都是有意义的
    普通变量和可选类型的区别,普通变量都是有意义的
    注意: Swift 的变量和C/OC的不一样,C/OC可以没有值,是一个随机值


    可选类型是安全的么? 是,可以通过可选绑定判断后再使用
    Swift的发明者完全是基于安全的考虑,当我们使用基本类型时完全不用考虑是否有值
    当我们使用可选类型时,总会记得先判断再使用,让程序时刻了解哪些有值,哪些没有值
*/

var opc: Int?

opc = 55

if let b = opc{

    print(opc!)

    print(b)
}

可选链

通过可选类型的变量来调用相应的属性和方法
可选链的返回值是一个可选值
格式:
可选值?.属性
可选值?.方法

class Person {

    var name: String

    init(name: String){

        self.name = name
    }
    func whoIam() ->String{

        print("my name is \(self.name)")
    
        return name
    }
}

var p0: Person?

var p1: Person = Person(name: "wocao")

p1.name = "made"

p1.whoIam()

/*
    如何通过可选类型来调用对应的方法和属性
    1、通过强制解包
        但是强制解包非常危险,如果可选类型没有值,会引发运行时错误
        p0!.name = "dede"

        p0?.whoIam()
    2、通过可选绑定,代码繁琐
        if let p = p0{
            p.name = "made"
            p.whoIam()
        }
    3、通过可选链,如果问号前面的变量没有值,整个可选链会失效
        p0 = p1
        p0?.name = "dedede"
        p0?.whoIam()
    可选链的返回值会自动包装成一个可选值
    因为可选链可用能失效
    所以返回值可能有值,也可能没有值
    要想表达有值或者没有值,只能用可选值,所以返回值会自动包装成一个可选值
*/

print(p0?.name)

print(p0?.whoIam())

print(p1.name)

var a: String? = p0?.name

p0?.name = "ww"

var b: String = p1.name

可选链调用下标索引

格式:
可选值?[]

struct Student {

    var name:String = "enen"

    var math:Double = 99.0
    var chinese: Double = 98.0
    var english: Double = 97.0

    /*
        要想实现下标访问,必须实现subscript方法
        如果想要通过下标访问,必须实现get方法
        如果想要通过下标赋值,必须实现set方法
    */

    subscript(course: String) ->Double?{

        get{
    
            switch course{
            case "math":
                return math
            case "chinese":
                return chinese
            case "english":
                return english
            default:
                return nil
        
            }
        }
    
        set{
    
            switch course{
            case "math":
                // 因为返回的是可选类型
                math = newValue!
            case "chinese":
                chinese = newValue!
            case "english":
                english = newValue!
            default:
                print("not found")
            }
    
        }
    }
}

var stu: Student? = Student()

// 可选链调用下标索引不需要,直接在问号后面加上[]即可
print(stu?["math"])

// 利用可选链赋值,注意:早先版本中不能利用可选链赋值
stu?.name = "hehe"

print(stu?.name)

// 利用可选链给下标赋值

stu?["math"] = 88

print(stu?["math"])

/*
    判断赋值操作是否成功,可选链的赋值操作也有返回值
    如果赋值成功,会返回一个可选类型
    返回()?也就是是Void?代表成功
    返回nil代表失败
*/

let res: Void? = stu?.name = "haha"

print(res)

stu = nil

let res1: Void? = stu?.name = "haha"

print(res1)

多层可选链

单层:可选值?.属性
多层: 可选值?.属性.属性?.属性 或者 可选值?.属性?.属性?.属性

class A {

    var name: String = "heheda"
}
class B {

    var a1: A?
}

class C {

    var b1: B = B()
}

class D {

    var c1: C?
}

var a1 = A()

var b1 = B()

var c1 = C()

var d1 = D()

d1.c1 = c1

// 通过d直接给b赋值,由于D中的C是可选值,所以需要在C后面加上?
d1.c1?.b1.a1 = a1

// 通过d直接获取a中的name,其实只需要在可选值后面加上问号即可,如果可选值不存在,那么后面的链失效

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

推荐阅读更多精彩内容