五、swift3.0閉包和懶載入
阿新 • • 發佈:2019-01-03
一、閉包的使用
與 OC中的Block類似,閉包主要用於非同步操作執行完成後的程式碼回撥,網路訪問結果以引數的形式傳遞給呼叫方
在OC中block是匿名的函式;在swift中閉包是特殊的函式
回撥的特點:以引數回撥處理結果;返回值為Void
1、閉包的定義
閉包 = { (行參) -> 返回值 in
// 程式碼實現
}
//1、定義一個常量記錄函式 func sum(n : Int, m : Int) -> Int { return m + n } //swift中函式本身就可以當作引數被定義和傳遞 let f = sum f(10, 20) //2、定義一個最簡單的閉包,() -> () 沒有引數,沒有返回值 let p = { print("hhah") } p() //3、定義一個帶引數的閉包 //通過“in”關鍵字,對閉包的定義和實現進行分割,沒有引數沒有返回值可以省略in // {形參列表 返回值型別 -> in 實現程式碼} let p2 = {(x : Int) -> () in print(x) } p2(123) //4、定義一個帶引數和返回值的閉包 let p3 = {(x : Int) -> Int in return x + 10 } print(p3(23)) let p1 = { () -> () in print("沒有引數,沒有返回值的閉包") } let p2 = { print("沒有引數,沒有返回值的閉包簡寫") } //注:在OC中{}用來分隔作用域的,而在swift中,表示一個閉包
2、閉包的使用
//作為函式的返回值,進行回撥操作 class Human: NSObject { func loadData(callBack : @escaping () -> ()) { DispatchQueue.global().async { () -> Void in print("載入資料的執行緒:\(Thread.current)"); DispatchQueue.main.async(execute: { print("更新UI的執行緒:\(Thread.current)") callBack() }) } } } override func viewDidLoad() { super.viewDidLoad() let per = Human() per.loadData { print("獲取到資料,重新整理UI") } } //結果: 載入資料的執行緒:<NSThread: 0x60000006c680>{number = 3, name = (null)} 更新UI的執行緒:<NSThread: 0x6000000639c0>{number = 1, name = main} 獲取到資料,重新整理UI
3、尾隨閉包
如果一個函式的最後一個引數是閉包,則函式的引數可以提前結束,最後一個引數直接使用{}包裝閉包的程式碼
let per = Human() //1、正常呼叫物件的函式 per.loadData(callBack: { () -> () in print("獲取到資料,重新整理UI") }) //2、尾隨閉包的改進:函式的引數可以提前結束,後面直接跟上一個閉包包裝程式碼 per.loadData() { () -> () in print("獲取到資料,重新整理UI") } //3、簡寫 per.loadData { print("獲取到資料,重新整理UI") }
4、閉包的迴圈引用
class ViewController: UIViewController {
//定義一個閉包屬性
var completion : (() -> ())?
override func viewDidLoad() {
super.viewDidLoad()
//如果記錄了閉包屬性,然後在閉包中又使用了self,則產生了迴圈引用
//解決閉包中的迴圈引用
//方法一:
//weak只能修飾var,不能修飾let,因為如果weak的指標在執行時會被修改,會自動設定為nil
weak var weakself = self
loadData {
//!:強制解包,必須有值,如果解包的值為nil,則崩潰
//?:可選解包,如果解包為nil,則不會執行後面的內容
print(weakself?.view ?? "")
}
//方法二:推薦
//[weak self]表示閉包中的self都是若引用
loadData { [weak self] in
print(self?.view ?? "")
}
//方法三:類似OC中的unsafe_unretained,常用
//[unowned self]表示閉包中的self為assign,如果self被釋放,則指標地址不會被釋放,容易導致出現野指標
loadData { [unowned self] in
print(self.view)
}
}
func loadData(complete: @escaping () -> ()) -> () {
//使用屬性記錄閉包
//completion = completion
DispatchQueue.global().async {
print("耗時操作")
DispatchQueue.main.async {
//回撥
complete()
}
}
}
deinit {
print("和dealloc一樣")
}
}
//在ARC中,weak本質是一個觀察者模式,一旦物件釋放,則把物件置為nil
//在MRC中,是通過assign進行若引用的,如果物件釋放,assign的指標還是指向該內地地址,會造成野指標
__weak typeof(self) weakSelf = self;
//__unsafe_unretained相當於assign,
__unsafe_unretained typeof(self) weak1Self = self;
二、懶載入
注:懶載入只會在第一次呼叫時執行建立物件,後面如果物件被釋放了,則不會再次建立。而oc中會再次建立。
//1、懶載入的定義
//懶載入的本質就是閉包
lazy var person : Human = {
print("懶載入的定義")
return Human()
}()
//2、懶載入改寫為閉包形式
let personFunc = { () -> Human in
print("懶載入 --> 閉包")
return Human()
}
lazy var personDemo : Human = self.personFunc()
//3、懶載入的簡單寫法
lazy var person2 : Human = Human()
三、UITableView的使用
import UIKit
class ViewController: UIViewController {
// MARK:- 懶載入
lazy var tableView : UITableView = {
let tempTableView = UITableView()
//可以做些事情
return tempTableView;
}()
lazy var tableView2 : UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
// MARK:- 設定UI
extension ViewController {
///設定UI
func setupUI() {
//1、設定tableView的屬性
tableView.frame = CGRect.init(x: 0, y: 0, width: view.bounds.size.width, height: view.bounds.size.height)
//2、設定資料來源
tableView.delegate = self;
tableView.dataSource = self;
//3、加入到控制器view
view.addSubview(tableView)
}
}
// MARK:- UITableView的代理方法
//extension:類擴充套件只能擴充方法,不能擴充屬性
extension ViewController : UITableViewDelegate, UITableViewDataSource {
/// UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("點選了\(indexPath)")
}
/// UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//1、建立cell
let idenftify = "cellID"
var cell = tableView.dequeueReusableCell(withIdentifier: idenftify)
if cell == nil {
cell = UITableViewCell.init(style: .default, reuseIdentifier: idenftify)
}
//2、賦值
cell?.textLabel?.text = "測試\(indexPath.row)"
//3、返回
return cell!
}
}
//使用執行時獲取當前類所有屬性陣列
class func propertyList() -> [String] {
//1、獲取類的屬性列表
var count : UInt32 = 0
//返回屬性列表陣列
let list = class_copyPropertyList(self, &count)
print("屬性的數量:\(count)")
//2、遍歷屬性列表
for i in 0...Int(count) {
//3、根據下標獲取屬性
let pty = list?[i]
//4、獲取屬性的名稱
let cName = property_getName(pty!)
//5、轉String
let name = String.init(cString: cName!)
// let name = String.init(describing: cName!)
print(name)
}
//3、釋放c語言的物件
free(list)
return []
}
//網路請求資料舉例
let url = URL.init(string: "https://www.baidu.com")
URLSession.shared.dataTask(with: url!) { (data, _, error) in
if error != nil {
print("網路載入失敗!")
}
guard let data = data else {
print("網路請求失敗")
return
}
let html = String.init(data: data, encoding: .utf8)
print(html ?? "")
}.resume()