Swift IOS问题从MasterView更新DetailView中的标签

时间:2018-11-13 09:31:49

标签: ios swift

我在stackoverflow上的第一个帖子,对不起,如果不正确

我正在XCode中使用“主/详细视图”模板。这是一个BLT Central应用程序,它会通知BLE设备上发生的事件。 我有一个主视图,使用

更新
    public  func    UpdateView() {
    tableView.beginUpdates()
    tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
    tableView.endUpdates()
}

这可以正常工作,并且只要BLE通知,TableView就会实时显示更新

但是,如果要显示细节视图,我还想实时更新。

我通过以下方式在DetailView中链接了标签:

@IBOutlet   weak var detailDescription: UILabel!

当MasterView绑定到DetailView时,它更新就很好了

但是,如果我在BLE通知到达时尝试更新Label,则@IBOutlet detailDescription变为nil,因此更新失败(标签未链接)

func UpdateDetail() {
    guard let label = detailDescription else {
        return; //Label not linked
    }
    label.text = "New Data"
}

UpdateDetail()函数还用于viewDidLoad()中,在这种情况下,它可以正常工作

真正奇怪的是,如果我在DetailView中添加一个计时器以进行更新

    var timer : Timer? = nil

@objc func fireTimer() {
    DispatchQueue.main.async {
        self.UpdateDetail()
    }
}

它工作正常,所以可能与从Detail类外部调用UpdateDetail()函数有关。

我已经检查了是否通过向属性添加didSet来重置detailDescription引用,并且在加载视图时仅对其调用了一次

猜猜我可以使用计时器来解决问题,但是我完全困惑为什么detailItem有时显示为nil,所以非常感谢您进行健全性检查。

更新已回到基本知识_______

因此,我现在回到标准的Apple Master-> Detail视图模板,并添加了一个简单的计时器来更新列表。 ListView可以很好地更新,但是它仍然不会动态更新详细视图。在自己的班级之外。

加载MainView后,我正在使用1秒钟的计时器,列表视图可以很好地更新,但是详细信息不能。

在调试时,它可以很好地进入configureView(),但是在第一个viewDidLoad()之后,detailDescriptionLabel为零

已经尝试了以下所有建议,但是在每种情况下,在初始加载后对标签的弱引用都为零

完全困惑

    @objc func doTimer() {
    for index  in 0..<objects.count {
        objects[index]=(objects[index] as! NSDate).addingTimeInterval(1)
    }
    tableView.beginUpdates()
    tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
    tableView.endUpdates()
    DispatchQueue.main.async {
        self.detailViewController?.configureView()
    }
}

MasterViewController.swift的完整代码,其余与标准模板相同。

import UIKit

class MasterViewController: UITableViewController {

var detailViewController: DetailViewController? = nil
var objects = [Any]()



override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    navigationItem.leftBarButtonItem = editButtonItem

    let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
    navigationItem.rightBarButtonItem = addButton
    if let split = splitViewController {
        let controllers = split.viewControllers
        detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
    }
//Added timer here
    _ = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(doTimer), userInfo: nil, repeats: true)
}

//Update data in list
@objc func doTimer() {
    for index  in 0..<objects.count {
        objects[index]=(objects[index] as! NSDate).addingTimeInterval(1)
    }
    tableView.beginUpdates()
    tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
    tableView.endUpdates()
    DispatchQueue.main.async {
        self.detailViewController?.configureView()
    }
}

override func viewWillAppear(_ animated: Bool) {
    clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed
    super.viewWillAppear(animated)
}

@objc
func insertNewObject(_ sender: Any) {
    objects.insert(NSDate(), at: 0)
    let indexPath = IndexPath(row: 0, section: 0)
    tableView.insertRows(at: [indexPath], with: .automatic)
}

// MARK: - Segues

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetail" {
        if let indexPath = tableView.indexPathForSelectedRow {
            let object = objects[indexPath.row] as! NSDate
            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
            controller.detailItem = object
            controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
            controller.navigationItem.leftItemsSupplementBackButton = true
        }
    }
}

// MARK: - Table View

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

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return objects.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

    let object = objects[indexPath.row] as! NSDate
    cell.textLabel!.text = object.description
    return cell
}

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    // Return false if you do not want the specified item to be editable.
    return true
}

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        objects.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .fade)
    } else if editingStyle == .insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
    }
}

}

2 个答案:

答案 0 :(得分:0)

我的答案基于所提供的Git存储库。

在MasterViewController中-您正在调用self.detailViewController?.configureView(),但从未分配明细控制器,并且由于它是nil,因此无法调用configureView函数。您可以通过设置prepare(for segue: UIStoryboardSegue, sender: Any?)

self.detailViewController = controller中进行此操作

这仍然无法帮助您更新标签值。

原因在于,在@objc func doTimer() {中,您总是将一个新的Date对象设置(覆盖)到数组中(可能的目的是更新相同引用的值)。因此,您分配给detailViewController的引用是不同的,并且您永远不会在计时器中更新detailItem。因此,调用configureView不会做任何更改,因为值保持不变。

答案 1 :(得分:-2)

之所以发生这种情况,是因为您的detailDescription标签“弱var detailDescription”较弱。而每次您编写此代码

guard let label = detailDescription else {
        return; //Label not linked
    }
    label.text = "New Data"

您创建一个新对象并为该对象分配值。因此detailDescription标签对象的原始值不会更改。每次更改其值时,请尝试使用相同的detailDescription对象。