Swift访问lazy var无限循环导致崩溃

时间:2018-02-28 02:28:30

标签: swift uitableview

我认为懒惰的var {}()应该运行一次。但今天我遇到这个问题困扰着我。我有任何想法。我哭了。

这是复制课:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private lazy var hotStockTableView: UITableView = {
        let tableView = UITableView()
        print("hotStockTableView ======> \(tableView) \n")
        tableView.delegate = self
        tableView.dataSource = self
        // Here cause crash.
        tableView.tableFooterView = UIView() // if comment this line, everthing is ok.
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        return tableView
    }()


    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(hotStockTableView)

        hotStockTableView.frame = view.bounds
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("tableView =====> \(tableView) \n")


        if tableView == hotStockTableView {
            return 5
        } else {
            return 0
        }
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        if cell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
        }
        cell?.textLabel?.text = "\(indexPath.row)"
        return cell!
    }
}

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:2)

问题是你创建表视图的闭包最终是递归的。

  • 当您在桌面上设置tableFooterView时,它会立即尝试找出是否应立即绘制/显示该页脚/屏幕。

  • 要知道页脚是否可见,表视图必须找出当前应显示的行数,因此它会向数据源(视图控制器)询问第一行中的行数部分

  • 在方法tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int中,您有if tableView == hotStockTableView {行。这会尝试访问仍未完成初始化的惰性hotStockTableView var,因为该闭包是首先调用此代码的

  • 因此,懒惰的var闭包再次启动并递归地反复执行相同的步骤,直到堆栈溢出并崩溃。

幸运的是,解决方案很简单。如果尚未设置数据源,则添加表视图页脚将永远不会调用您的行数数据源方法。因此,只需将延迟闭包中的代码顺序更改为以下内容:

private lazy var hotStockTableView: UITableView = {
    let tableView = UITableView()
    print("hotStockTableView ======> \(tableView) \n")
    tableView.tableFooterView = UIView()
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
    tableView.delegate = self
    tableView.dataSource = self
    return tableView
}()

现在你的代码工作得很好。

答案 1 :(得分:1)

关于lazy个变量有a good answer on SO

  

就线程安全而言,lazy var不是线程安全的   在斯威夫特。

     

这意味着如果两个不同的线程尝试访问相同的lazy var   同时,在这个变量初始化之前,它是   可能其中一个线程将访问部分构造   实例

我建议在创建delegate视图后尝试设置dataSourcelazy。在完全初始化之前,delegatedataSource可能会访问它。