【Swift编程基础】P41-50

视频:P41-50 日期:5.2


目录

P41:自动内存释放,反初始化器

1.自动引用计数ARC工作机制

2.强引用

P42:循环强引用,弱引用weak

1.循环强引用

2.弱引用

P43:无主引用unowned

 

P44:闭包循环引用,定义捕获列表

1.闭包循环引用

2.定义捕获列表

P45:可选链展开

P46:尾随闭包

P47:错误捕获和处理

P48:泛型类型限定,协议关联类型

1.泛型中的类型限定

2.协议中的类型限定

P49:访问权限简单说明

P50:总结


 

P41:自动内存释放,反初始化器

1.自动引用计数ARC工作机制

引用同一个对象

//1.自动引用计数ARC工作机制

import UIKit

class Test
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
}

var t1 = Test(name:"hello")

var t2 = t1

var t3 = t1

//这样的话t1 t2 t3 同时指向同一个对象
t3.name = "xiaohongmao"
print(t2.name)
/*
xiaohongmao
*/

ARC工作机制

//如果没有任何引用指向Test实例的时候,那么这个实例对象会自动销毁,该实例被释放

2.强引用

//只要有一个引用指向Test,那么Test就不会被销毁,除非全部断开

3.反初始器

//3.反初始器
//当一个实例对象被销毁的时候,就会调用反初始化器
import UIKit

class Test
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("Test被销毁 - " + self.name)
        
    }
}

var t1:Test? = Test(name:"hello")

t1 = nil
/*
Test被销毁 - hello
*/

P42:循环强引用,弱引用weak

1.循环强引用

循环强引用就是断开了直接的引用但是内部仍然存在相互引用。

在没有循环强引用下:被注释掉

import UIKit

//循环强引用
//弱引用weak

class TestA
{
    var name:String
    var ref:TestB? = nil
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("TestA的实例被释放 - " + self.name)
    }
    
}
class TestB
{
    var name:String
    var ref:TestA? = nil
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("TestB的实例被释放 - " + self.name)
    }
}

var testA:TestA? = TestA(name:"A")

var testB:TestB? = TestB(name:"B")


//循环强引用
//testA!.ref = testB
//testB!.ref = testA
testA = nil
testB = nil


/*
TestA的实例被释放 - A
TestB的实例被释放 - B
*/

取消注释之后,引发内部循环调用:

注意!!!:取消实例引用后,无法调用方法和属性

import UIKit

//循环强引用
//弱引用weak

class TestA
{
    var name:String
    var ref:TestB? = nil
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("TestA的实例被释放 - " + self.name)
    }
    
}
class TestB
{
    var name:String
    var ref:TestA? = nil
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("TestB的实例被释放 - " + self.name)
    }
}

var testA:TestA? = TestA(name:"A")

var testB:TestB? = TestB(name:"B")


//循环强引用
testA!.ref = testB
testB!.ref = testA

testA = nil
testB = nil

/*
*/
//无返回值
循环强引用示意图

断开所有引用:

var testA:TestA? = TestA(name:"A")

var testB:TestB? = TestB(name:"B")


//循环强引用
testA!.ref = testB
testB!.ref = testA

//断开引用
testA!.ref = nil
testB!.ref = nil

testA = nil
testB = nil
/*
TestA的实例被释放 - A
TestB的实例被释放 - B
*/

2.弱引用

弱引用就是TestA与TestB之间的引用不会影响ARC机制,强引用会影响,导致无法释放。

即释放的两种方法:1.变成弱引用2.直接断开,令之为nil,注意nil的前提是可选类型!!

import UIKit
//弱引用weak, 加关键字weak
class TestA
{
    var name:String
    var ref:TestB? = nil
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("TestA的实例被释放 - " + self.name)
    }
    
}
class TestB
{
    var name:String
    weak var ref:TestA? = nil  //弱引用加关键字weak!
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("TestB的实例被释放 - " + self.name)
    }
}

var testA:TestA? = TestA(name:"A")

var testB:TestB? = TestB(name:"B")


//循环强引用
testA!.ref = testB
testB!.ref = testA


//testA!.ref = nil
testA = nil

/*
TestA的实例被释放 - A
*/

 

P43:无主引用unowned

首先都是强引用,然后实例化属性ref:

import UIKit
//无主引用
class TestA
{
    var name:String
    var ref:TestB
    init(name:String)
    {
        self.name = name
    }
    
    deinit
    {
        print("TestA的实例被释放 - " + self.name)
    }
    
}
class TestB
{
    var name:String
    var ref:TestA
    init(name:String,ref:TestA)
    {
        self.ref = ref
        self.name = name
    }
    
    deinit
    {
        print("TestB的实例被释放 - " + self.name)
    }
}

var testA:TestA? = TestA(name:"A")

testA!.ref = TestB(name: "B", ref: testA!)
testA = nil
强引用,只有testA指向TestA

之后再逐一释放,非常麻烦:(后面会讲突出无主引用的便利)

var testA:TestA? = TestA(name:"A")

testA!.ref = TestB(name: "B", ref: testA!)

testA!.ref = nil //这一步就没有指向TestB的强引用了,TestB被释放

testA = nil
/*
TestB的实例被释放 - B
TestA的实例被释放 - A
*/
先释放TestB

 

P44:闭包循环引用,定义捕获列表

1.闭包循环引用

import UIKit

class Test
{
    var name:String
    //3-lazy保证用的时候进行初始化,一定要初始化,保证安全性
    
    lazy var data:() -> Void = {() -> Void in  //2-闭包,匿名函数
        print(self.name)
        
    }
    
    init(name:String)
    {
        self.name = name
    }
    
    deinit{
        print("Test的实例被释放 - " + self.name)
    }
    
}

var t:Test? = Test(name:"hello")

t!.data()
//4-若注释掉这一行,则会打印Test的实例被释放
//5-但目前导致Test还没有被释放的原因就是还有一个强引用指向Test,就是self.name这个闭包里的引用


t = nil

//1-到这里结束,Test对象被释放,然后加一个闭包,data
//6-下一步是要定义捕获列表,来解决这个问题
/*
hello
*/
//输出的是hello,而不是被释放

2.定义捕获列表

1.用无主引用


import UIKit
//定义捕获列表
class Test
{
    var name:String
    //1-加入一个列表
    lazy var data:() -> Void = {[unowned self]() -> Void in //2-给匿名函数传入一个无主引用的对象
        print(self.name)
        
    }
    
    init(name:String)
    {
        self.name = name
    }
    
    deinit{
        print("Test的实例被释放 - " + self.name)
    }
    
}

var t:Test? = Test(name:"hello")

t!.data()
t = nil
//被释放掉了

/*
hello
Test的实例被释放 - hello
*/

2.或者用弱引用(一般用无主引用比较好)

import UIKit
//定义捕获列表
class Test
{
    var name:String
    //1-加入一个列表
    lazy var data:() -> Void = {[weak self]() -> Void in //2-给匿名函数传入一个无主引用或者weak引用的对象
        print(self!.name) //注意weak引用可能没值,所以要加!号
        
    }
    
    init(name:String)
    {
        self.name = name
    }
    
    deinit{
        print("Test的实例被释放 - " + self.name)
    }
    
}

var t:Test? = Test(name:"hello")

t!.data()
t = nil
//被释放掉了
/*
hello
Test的实例被释放 - hello
*/

 

P45:可选链展开

可选链展开应该就是最后的!和?的选择,如果不确定有没有值,用?不会报错,但如果是nil,用!的话会报错。

import UIKit

class Data
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
    func play()
    {
        print(self.name)
    }
}

class Test
{
    var name:String
    var data:Data? = nil
    
    init(outname name:String,data:Data) //将Data的一个实例化对象传到Test的初始化器里面去
    {
        self.name = name
        self.data = data
    }
    deinit
    {
        print("Test的实例被释放 - " + self.name) //反初始化器
    }
}

var t:Test? = Test(outname:"hello",data:Data(name:"world"))

//Data(name:"AAA").play()

t!.data?.play()
//(t?.data)?.play()

/*
world
*/

 

P46:尾随闭包

很多例子:

import UIKit

//尾随和闭包
func play1(param1:String,param2:(String) -> Void)
{
    param2(param1 + " - Swift")
}

play1(param1: "hello", param2: {(data:String) -> Void in
    print(data)
})

//满足尾随闭包的条件
//1-传入的函数参数类型一定在最后一位
//回车后将括号内的实现方式移到了括号外面
play1(param1: "world") { (data) in
    print(data)
}

func play2(param:(String)->String)
{
    var value = param("swift")
    print("返回值 = " + value)
}
play2(param: {(data)->String in
    return data + " - ios"
})

play2(){(data) -> String in
    return data + " - macos"
}

play2(){(data) -> String in
    return data + " - apple"
}
//只有一个函数类型的参数,所以第一个括号就不写了

func play3(param:() -> Void)
{
    param()
}

play3(param:{() -> Void in
    print("play3")
})

play3{
    print("play3")
}

func play4(param:() -> String)
{
    var value = param()
    print("value = " + value)
}

play4(param:{() -> String in
    return "hello world"
})

play4(){() -> String in
    return "hello world"
}
play4{() -> String in //前面没有参数,()可以去掉
    return "hello world"
}
play4{              //有return,一堆可以去掉
    return "hello world"
}

//下面是不带尾随闭包的多参数函数,不是尾随闭包
func play5(param1:(Int) -> Void,param2:Int)
{
    param1(param2 * 2)
}

play5(param1:{(data:Int) -> Void in
    print(data)
},param2: 100)

play5(param1:{(data)in
    print(data)
},param2: 100)

/*
hello - Swift
world - Swift
返回值 = swift - ios
返回值 = swift - macos
返回值 = swift - apple
play3
play3
value = hello world
value = hello world
value = hello world
value = hello world
200
200
*/

 

P47:错误捕获和处理

import UIKit

//先用枚举定义一个错误

enum TestError:String,Error
{
    case error1 = "错误1"
    case error2 = "错误2"
}

func play(param:Int) throws //抛出错误是复数throws
{
    if(param<0)
    {
        throw TestError.error1
    }
    else if (param >= 0 &&/*并且*/ param<=10)
    {
        throw TestError.error2
    }
    
    print("正常执行")
}


do
{
    try play(param:-1)
}
catch TestError.error1
{
    print(TestError.error1.rawValue)
}
catch TestError.error2
{
    print(TestError.error2.rawValue)
}
defer
{
    print("defer")
}



//play(param:0)
//报错Error:Call can throw but is not marked with 'try'

/*
错误1
defer
*/

也可以把错误传成一个可选类型,进行返回:

do
{
    var value = try play(param:100)  //接收一下
    print(value)    //和do catch 没什么关系,放外面也可以
}
catch TestError.error1
{
    print(TestError.error1.rawValue)
}
catch TestError.error2
{
    print(TestError.error2.rawValue)
}
defer
{
    print("defer")
}

/*
正常执行
把错误转成一个可选类型
defer
*/
也可以直接.error来代替TestError.error

P48:泛型类型限定,协议关联类型

1.泛型中的类型限定

import UIKit

class Data
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
}

func play<T:Data>(param:T) //这里T要缩小范围否则没有意义,就叫泛型的类型限定
{
    var a = param as! Data //进行强制类型转换成Data类型,调用name属性
    print(a.name)
}

play(param:Data(name:"hello"))
/*
hello
*/

2.协议中的类型限定

例1:限定函数参数类型

import UIKit

class Data
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
}

protocol Test
{
    associatedtype D  //定义了协议中的一个未知类型
    func play(param:D)
}

class Student:Test
{
    func play(param:String){
        print(param)
    }
}

var s = Student()
s.play(param: "没有定义D的类型,给play传一个字符串")
/*
hello
*/

例2:限定D的类型

import UIKit

class Data
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
}

protocol Test
{
    associatedtype D: Data //定义了协议中的一个未知类型
    func play(param:D)
}

class Student:Test
{
    func play(param:Data){
        print(param.name)
    }
}

var s = Student()
s.play(param: Data(name: "swift"))
/*
swift
*/

 

P49:访问权限简单说明

访问权限

1: private

private访问级别所修饰的属性或者方法只能在当前类里访问。

2: fileprivate

fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问。

3: internal (默认访问级别,internal修饰符可写可不写)

internal访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。如果是框架或者库代码, 则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。如果是App代码,也是在整个App代码,也是在整个App内部可以访问。

4: public

可以被任何人访问。但其他module中不可以被override和继承,而在module内可以被override和继承。

5: open

可以被任何人使用,包括override和继承。

P50:总结

4.25 - 5.2

完结撒花   🎉

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张小怪的碗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值