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 UIKit

class 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 UIKit

class 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 UIKit

class 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 UIKit

class 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中规定访问权限的关键词有 internalopenprivate、 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小案例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值