首页 > 学院 > 开发设计 > 正文

Swift3.0从入门到放弃(四)-基础最终篇

2019-11-08 00:30:38
字体:
来源:转载
供稿:网友
Swift中的闭包 闭包衍生的循环引用问题闭包循环引用问题另一种解决写法(简便写法)尾随闭包Swift中的懒加载Swift中的访问权限Swift中零散知识点Swift3.0小案例

Swift中的闭包

Swift中的闭包和OC中的block大致相同,OC中的block相当于匿名函数,而Swift中的闭包也相当于特殊的函数。 闭包的数据类型格式为: (参数列表) -> (返回值类型) 下面用一个异步网络请求的案例来简单使用一下闭包:首先创建模拟网络请求类⬇️import UIKit// 模拟网络工具类class HWHttpTools: NSObject { // 模拟网络工具类提供的网络请求接口函数 // 注意点: 1.Swift中闭包的参数必须设置为内部参数(在参数名前加上下划线) // 2.闭包中多个参数用逗号隔开 // 3.Swift3.0中GCD异步函数的写法发生改变 DispatchQueue.global().async { 异步执行代码块 } // 4.Swift3.0中查看当前线程 Thread.current // 5.如下,Swift3.0中如果在当前函数内直接调用闭包就不需要加 @escaping 来修饰闭包;但是如果在其他闭包内调用,就必须在闭包前面添加 @escaping(逃逸)关键字 func requestWith(url : String, _ finishedCallBlock : @escaping (_ succeed : Bool, _ data : Data?)->()) { // 发起异步请求 DispatchQueue.global().async { PRint("发起异步请求 - /(Thread.current)") // 回到主线程 DispatchQueue.main.async { print("请求成功回到主线程 - /(Thread.current)") // 闭包回调 finishedCallBlock(true, nil) } } }}在控制器中点击view利用网络工具类发起网络请求import UIKitclass ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } // 点击屏幕 发送网络请求 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { HWHttpTools().requestWith(url: "服务器url字符串") { (succeed : Bool, data : Data?) in if succeed { print("网络请求成功 - /(Thread.current)") } } }}点击view打印结果⬇️发起异步请求 - <NSThread: 0x6080002613c0>{number = 3, name = (null)}请求成功回到主线程 - <NSThread: 0x60000007a9c0>{number = 1, name = main}网络请求成功 - <NSThread: 0x60000007a9c0>{number = 1, name = main}

闭包衍生的循环引用问题

在上面的案例中,我们故意在控制器闭包回调中添加一句更改view视图背景颜色的代码,看看是否会发生循环引用问题。(我们把网络工具类对象设置成控制器的一个强引用属性)import UIKitclass ViewController: UIViewController { // 网络工具类属性 var httpTools : HWHttpTools? override func viewDidLoad() { super.viewDidLoad() } // 点击屏幕 发送网络请求 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // 网络工具类属性赋值 httpTools = HWHttpTools() httpTools?.requestWith(url: "服务器url字符串") { (succeed : Bool, data : Data?) in // 更改了view视图的背景颜色 // 在闭包内调用当前类的属性,必须加 self. // 那么在这个闭包中调用了self会不会发生循环引用? // *** 答案是否定的,当前控制器强引用工具类对象,闭包强引用当前控制器,但是工具类对象并没有强引用闭包,所以并不会发生循环引用。*** self.view.backgroundColor = UIColor.red } }}但是万一在闭包中发生了循环引用问题,在Swift当中我们应该怎么处理呢?首先我们先让工具类对象强引用闭包。⬇️import UIKit// 模拟网络工具类class HWHttpTools: NSObject { var finishedCallBlock : ((_ succeed : Bool, _ data : Data?)->())? func requestWith(url : String, _ finishedCallBlock : @escaping (_ succeed : Bool, _ data : Data?)->()) { // 强应用闭包 self.finishedCallBlock = finishedCallBlock // 发起异步请求 DispatchQueue.global().async { print("发起异步请求 - /(Thread.current)") // 回到主线程 DispatchQueue.main.async { print("请求成功回到主线程 - /(Thread.current)") // 闭包回调 finishedCallBlock(true, nil) } } }}然后再控制器中出现循环引用,我们采取使用在闭包外部将控制器self赋值给weak修饰的变量来阻断闭包对控制器的强引用。⬇️import UIKitclass ViewController: UIViewController { // 网络工具类属性 var httpTools : HWHttpTools? override func viewDidLoad() { super.viewDidLoad() } // 点击屏幕 发送网络请求 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // 网络工具类属性赋值 httpTools = HWHttpTools() // 注意: weak修饰的标识符可能为nil,所以weakSelf为可选类型 // 注意: weak只能修饰变量 weak var weakSelf = self httpTools?.requestWith(url: "服务器url字符串") { (succeed : Bool, data : Data?) in weakSelf?.view.backgroundColor = UIColor.red } }}

闭包循环引用问题另一种解决写法(简便写法)

import UIKitclass ViewController: UIViewController { // 网络工具类属性 var httpTools : HWHttpTools? // 点击屏幕 发送网络请求 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // 网络工具类属性赋值 httpTools = HWHttpTools() // 解决循环引用的方式二 在闭包的{}大括号内的开头 写上[weak self] 然后再比包内使用 self 就不会发生循环引用,切记这时闭包内使用的 self 为可选类型。 // 以上写法相当于在闭包外部写上 weak var weakSelf = self,然后在闭包内部使用 weakSelf 替代 self 原理一样。 httpTools?.requestWith(url: "服务器url字符串") { [weak self] (succeed : Bool, data : Data?) in self?.view.backgroundColor = UIColor.red } } // 析构函数 deinit { print("控制器销毁") }}PS : 还有一种写法是将上面的 [weak self] 改写成 [unowned self] 效果是一样的,但是使用 unowned 是很危险的容易出现操作野指针,unowned 的意思跟OC当中的__unsafe_unretained一样 只不过保证 self 不被销毁就可以安全使用。

尾随闭包

当函数参数中的闭包参数是最后一个,在函数调用时闭包参数整个大括号可以写在参数列表小括号外面(紧跟在后面)// 写法一HWHttpTools().function(name: "参数一", { // 闭包代码块})// 写法二 尾随闭包HWHttpTools().function(name: "参数一") { // 闭包代码块}当函数只有一个参数,且是闭包参数,那么可以在函数调用的时候省去()小括号,如下3种写法均可:HWHttpTools().function({ //普通写法})HWHttpTools().function() { // 尾随闭包写法}HWHttpTools().function { // 省略小括号的尾随闭包写法 }

Swift中的懒加载

懒加载特性 : 1.用到时才会加载;2.程序运行过程中只会创建一次在OC中的懒加载我们通常是通过重写其getter方法来实现的,但是在Swift中专门提供了一个关键字 lazy 来修饰懒加载属性,具体写法如下:lazy var names : [String] = Array() // 懒加载数组写法一lazy var items : [String] = { // 懒加载数组写法二 let items : [String] = Array() return items}()在开发中,很多控件也使用懒加载,用到即加载到内存中。lazy var btn : UIButton = UIButton() // 只是为了初始化控件 不进行其他设置的懒加载写法lazy var btn : UIButton = { let btn = UIButton() // 懒加载设置其他属性写法 btn.setTitle("按钮", for: .normal) btn.setBackgroundImage(UIImage(named: "xx.png"), for: .normal) return btn}()

Swift中的访问权限

在Swift3.0中规定访问权限的关键词有 internal 、 open、 private、 fileprivate。这些访问权限关键词不仅可以修饰属性,也可以修饰方法和类。internal : 默认修饰词(属性、类、方法默认权限修饰词),表示在同一个模块(target、项目、资源包)中都能够访问。open : 表示跨项目(target、项目、资源包)都能够使用。private : 表示只能在当前类中访问。fileprivate : 表示只能在当前文件中使用。

Swift中零散知识点

1.在Swift开发中,并不是所有的方法都写在一个类中,这样可读性也不会很好。如果能够灵活运用延展,就可以有效提高代码的可读和美观性。但是注意 : 在延展中的方法不能用private修饰,不然在当前类中也无法访问,只能在延展中使用,但是可以用fileprivate修饰。2.在Swift开发中,监听方法若用 private 或 fileprivate 修饰必须前面加上 @objc 修饰词。(什么是监听方法 : 比如写在#selector()里面的按钮的监听方法)3.在Swift中分栏注释(提高代码阅读性) // MARK: info ,类似于OC项目中的 #pragma mark - info 的作用。

Swift3.0小案例

小案例目的在于综合运用Swift3.0写一个页面,中间设计网络请求、控件搭建、图片加载、转换数据模型等。

源代码地址 : https://github.com/IMLoser/Swift3.0_Demo

Swift3.0小案例


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表