CollectionView丢失了对数据模型的引用

时间:2018-07-24 16:02:28

标签: ios swift collectionview

现在在同一问题上停留了几天。

我有一个ViewControllerA类,它用作CollectionView委托和数据源。 CollectionView通过情节提要进行连接。 ViewControllerA类包含提供CollectionView的数据模型。

每次ViewControllerA首次加载时,它都会连接到数据库,并根据需要将信息加载到数据模型(userDictionary)中。一旦控制器加载了所有数据,它将重新加载CollectionView,并触发同步方法来侦听数据库中的任何更改,以相应地更新userDictionary,并重新加载collectionView中的各个项目。

到目前为止,一切正常。

当我过渡到其他不同的ViewController类时,例如说ViewControllerB类,我是将userDictionary的副本从ViewControllerA传递给prepareForSenderA中的ViewControllerB,然后通过prepareForSenderB传递回ViewControllerA。

这是奇怪的行为。当我过渡到ViewControllerA类时,CollectionView可以很好地使用传递给ViewControllerB的相同数据,但是无法加载同步方法在ViewControllerA中观察到的任何新更改。

我知道同步方法仍然可以正常工作,因为当我将其打印到ViewControllerA中时,所有新数据都会在调试器中显示。而且我知道我的同一个控制器类中的userDictionary数据模型正在接收这些更新,这是因为didSet观察程序正在打印出userDictionary的最新状态。

奇怪的是,每当我在ViewControllerA类中打印出数据模型的内容时,它就会打印出传递给ViewControllerB类时存在的模型的旧状态。即使didSet观察者刚刚证明该模型实际上已更新!

几乎就像ViewControllerA类以某种方式保留了对数据模型的引用(当它传递给ViewControllerB时一样),并且以某种方式“丢失”了对模型自身的引用(当该模型被传回时) 。

另一注:如果我一直呆在ViewControllerA中,并且不来回传递userDictionary,则不会再遇到此问题。

下面的代码总结了我如何来回传递数据:

View Controller A类:

class ViewControllerA: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

//MARK: Data Structures
var userDictionary = [[String: String]]() { didSet { print("userDictionary.count from DIDSET,", userDictionary.count)}}
//prints out: 9

//MARK: Initialization
override func viewDidLoad() {
    self.loadUserDictionaryFromDatabase()
}

func loadUserDictionaryFromDatabase() {
    //code that loads information from a database
    //var objectInstance["name"] = firstName
    //self.userDictionary.append(objectInstance)
    print("loader observed numberOfItems", numberOfItems)
    //...once data is fully loaded
    self.syncDataFromDatabase()
}

func syncDataFromDatabase() {
    //sync new data from database
    //var newObjectInstance["newName"] = newFirstName
    //self.userDictionary.append(newName)
    print("syncer observed newNumberOfItems", newNumberOfItems)
}

//MARK: View Controller Transitions
@IBAction func segueAtoB(_ sender: Any) {
    self.performSegue(withIdentifier: "segueAtoB", sender: self)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    //Segue from VCA to VCB
    if segue.identifier == "segueAtoB" {

        let controller = segue.destination as! ViewControllerA

        //Pass initialized userDictionary from VCA to VCB
        controller.userDictionary = self.userDictionary
    }
}

//MARK: Dummy Test Number of Items in UserDictionary
@IBAction func printMostUpToDateNumberofItemsInDictionary(_ sender: Any) {
    print("userDictionary.count from TEST,", userDictionary.count)
}

}

View Controller B类:

ViewControllerB类:UIViewController {

//MARK: Data Structures
var userDictionary = [[String: String]]()

//MARK: View Controller Transitions
@IBAction func segueBtoA(_ sender: Any) {
    self.performSegue(withIdentifier: "segueBtoA", sender: self)
}


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    //1. Segue to Home-Screen Controller
    if segue.identifier == "segueBtoA" {

        let controller = segue.destination as! ViewControllerB
        controller.userDictionary = self.userDictionary
    }
}

}

打印结果:

步骤1:从View Controller A开始

  1. 加载程序观察到的numberOfItems = 9
  2. DIDSET中的userDictionary.count,9
  3. syncer观察到newNumberOfItems = 1
  4. userDictionary.count来自DIDSET = 10(10 = 9 +1)-通过
  5. userDictionary.count从TEST = 10(10 = 9 +1)-通过

步骤2:从A到B连续

viewControllerB.userDictArray = viewControllerA.userDictArray

第3步:从B到A的顺序

viewControllerA.userDictArray = viewControllerB.userDictArray

步骤4:观察调试器输出

  1. DIDSET中的userDictionary.count,10
  2. syncer观察到newNumberOfItems = 1
  3. userDictionary.count来自DIDSET = 11(10 = 10 +1)-通过
  4. TLI中的
  5. userDictionary.count = 10(10!= 10 +1)-失败 (diSet仅更新了userDictionary.count时,这行是怎么发生的?)

使用UUID的调试器输出:

第1步:在View Controller A中启动

  1. 加载程序观察到numberOfItems,A74593E1-1231-41BE-A5DF-693591F998E4
  2. DIDSET中的userDictionary.count,A74593E1-1231-41BE-A5DF-693591F998E4
  3. syncer观察到newNumberOfItems,A74593E1-1231-41BE-A5DF-693591F998E4
  4. DIDSET中的userDictionary.count,A74593E1-1231-41BE-A5DF-693591F998E4
  5. test中的userDictionary.count,A74593E1-1231-41BE-A5DF-693591F998E4

第4步:观察调试器输出

  1. DIDSET中的userDictionary.count,A74593E1-1231-41BE-A5DF-693591F998E4
  2. syncer观察到newNumberOfItems,A74593E1-1231-41BE-A5DF-693591F998E4
  3. DIDSET中的userDictionary.count,A74593E1-1231-41BE-A5DF-693591F998E4
  4. TEST中的userDictionary.count,28D817D9-B53D-47D8-A3EF-2F7DDE6460FC

1 个答案:

答案 0 :(得分:1)

我真的认为您需要/想要使用“放松”功能。

ViewControllerA中添加以下功能:

@IBAction func returnFromB(_ segue: UIStoryboardSegue) {
    if let vcDest = segue.destination as? ViewControllerA,
        let vcSource = segue.source as? ViewControllerB {
            // pass userDictionary from VCB back to VCA
            vcDest.userDictionary = vcSource.userDictionary
        print("unwind segue from B")
    }
}

然后,通过Ctrl-Drag将其从View Controller图标连接到情节提要中ViewControllerA顶部的Exit图标。给它一个segue标识符。

现在,您可以在ViewControllerB中致电:

self.performSegue(withIdentifier: "unwindSegueBtoA", sender: self)

,并且returnFromB()中的ViewControllerA函数将处理回传数据。

这是一个基本示例:https://github.com/DonMag/DataPass

另一个(可能更好)的选择是创建一个“数据管理器”类,并从每个控制器的该类中设置/获取数据,而不是来回传递。