视频:P41-50 日期:5.2
目录
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

之后再逐一释放,非常麻烦:(后面会讲突出无主引用的便利)
var testA:TestA? = TestA(name:"A")
testA!.ref = TestB(name: "B", ref: testA!)
testA!.ref = nil //这一步就没有指向TestB的强引用了,TestB被释放
testA = nil
/*
TestB的实例被释放 - B
TestA的实例被释放 - A
*/

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
*/

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
完结撒花 🎉