Swift Lazy的陷阱

最近我们项目线上出现了几个Swift代码的crash问题,和大家一起分析一下问题的原因。

首先看代码:

class DEFContactDetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
	 
	 deinit {
        tableView.delegate = nil
        tableView.dataSource = nil
    }

    lazy var tableView = UITableView(frame: view.bounds, style: .plain).then {
        $0.backgroundColor = UIColor.white
        $0.estimatedRowHeight = 44
        $0.rowHeight = UITableViewAutomaticDimension
        $0.dataSource = self
        $0.delegate = self
        $0.tableFooterView = UIView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        title = "联系人"

        view.addSubview(tableView)
        tableView.mas_makeConstraints { maker in
            maker?.edges.equalTo()(view)
        }
        
        //....
    }
}
复制代码

这是一个联系人详情页面,主要有一个UITableView来展示内容,只不过tableView是一个lazy属性,在构造tableView时设置它的一些属性,并绑定了dataSourcedelegate。另外在deinit方法中将dataSourcedelegate置空。

这里有人可能要说deinit方法中的事情其实没必要做了,因为现在UITableViewdelegatedataSource已经是weak的了。没错,但是delegatedataSource在iOS9以后才是weak,在iOS8以前还是assign的,这里在deinit中手动将其置为nil也是为了兼容iOS8的系统。

如果在某种情况下创建一个TestController的实例,但是没等TestController的view显示出来实例就被释放的话上面的代码就会crash。

let controller = DEFContactDetailViewController()
if (/*hasNavigationController*/) {
	//push controller
}
复制代码

如果上面的if条件不成立的话相当于这样:

let controller = DEFContactDetailViewController()
controller = nil 
复制代码

这种情况下发生crash的原因会是一下两种情况:

  • 原因1: 是因为如果执行deinit时tableView是nil的话,deinit中的代码实际上相当于懒加载调用tableView的初始化方法,在初始化方法中设置了delegate和dataSource,之就相当于OC中在dealloc中访问weak的self一样会crash。

  • 原因2:如果这时controller的view还没构造出来的话view属性这时还是nil,上面的 let tableView = UITableView(frame: view.bounds, style: .plain)这一行中访问了view.bounds,这就相当于对view属性做强制解包。可想而知对nil强制解包的后果,自然是crash。

解决方案:

  1. 将deinit中 tableView.delegate = nil tableView.dataSource = nil这两行删掉,当然这样也就抛弃了对iOS8的兼容

  2. 不用lazy,将tableView的构造逻辑直接写在viewDidLoad方法中

  3. 希望Swift中能够像OC那样只访问实例而不会触发lazy调用的访问方式,

- (void)dealloc {
    _tableView.delegate = nil;
    _tableView.dataSource = nil;
}
复制代码

对于这种lazy的用法我相信在大家的项目中应该也会有,只不过没有遇到我这种会出crash的场景。可惜目前Swift并没有第三点中提到的这个和OC类似的特性。所以大家在用lazy的时候特别是类似UITableView这类的对象一定要特别小心了,避免掉进这个陷阱中去。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值