一、闭包的使用
与 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中,表示一个闭包
//作为函数的返回值,进行回调操作
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")
}
}
//结果:
加载数据的线程:{number = 3, name = (null)}
更新UI的线程:{number = 1, name = main}
获取到数据,刷新UI
let per = Human()
//1、正常调用对象的函数
per.loadData(callBack: { () -> () in
print("获取到数据,刷新UI")
})
//2、尾随闭包的改进:函数的参数可以提前结束,后面直接跟上一个闭包包装代码
per.loadData() { () -> () in
print("获取到数据,刷新UI")
}
//3、简写
per.loadData {
print("获取到数据,刷新UI")
}
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()
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()