在委托方法中引用时,弱var出口丢失(= nil)

时间:2019-05-02 20:05:32

标签: swift

我的类中有一个UICollectionView声明为 @IBOutlet弱varartworkCollectionView:UICollectionView!

在此类中,有一个委托方法被其他两个View Controller调用,其中一个VC是一个弹出窗口,另一个是普通的VC。

委托方法从数据库中获取一些数据,然后更新在闭包内部调用的集合视图: self.artworkCollectionView.reloadData()

当弹出的VC调用委托方法时,一切都很好。但是,当普通VC到达self.artworkCollectionView.reloadData()时,委托方法被常规VC调用时,它将收到臭名昭著的致命错误:意外地找到nil,同时隐式展开了Optional值。

我已经检查了对单元复用ID的所有引用,并且都正确。我怀疑因为UICollectionView被声明为弱变量,所以当我从当前类转到弹出窗口,然后弹出窗口调用委托方法时,引用不会丢失,而是当我从当前类转到正常对象时VC,然后普通的VC调用委托方法,丢失了对我的弱var的引用,因此它被“视为”为nil。

@IBOutlet weak var artworkCollectionView: UICollectionView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Set up
    artworkCollectionView.dataSource = self
    artworkCollectionView.delegate = self
    artworkCollectionView.isUserInteractionEnabled = true
    artworkCollectionView.allowsSelection = true
    artworkCollectionView.register(UINib(nibName: 
    "MyCollectionViewCell", bundle: nil), 
    forCellWithReuseIdentifier: "cell")
}


// delegate method
func reloadCollections() {

    retrieveAlbumRatings { (isAlbum) in
        if isAlbum {

            self.retrieveAlbumData(completion: { (isFinished) in

                if isFinished {
                    // Reload collection views
                    self.artworkCollectionView.reloadData()

                }
            })
        }
    }
}

如果我是对的,我的问题是:如何给弱varartworkCollectionView:UICollectionView!一个强引用,以便它不会在从当前类到常规VC以及返回的流中丢失?

编辑:这是我到目前为止所尝试的:

  1. 从出口声明中删除“弱”,使其成为:@IBOutlet var ArtworkCollectionView:UICollectionView! 但是我遇到了同样的错误

  2. 我通过override performSegue将artworkCollectionView传递给了普通的VC,然后将其作为委托方法的参数传递回去。这不会给我致命错误,但也不会重新加载UICollectionView,因为我认为无论如何,对UICollectionView出口的弱引用都丢失了。

感谢您的帮助(免责声明:我对Swift还是很陌生。)

2 个答案:

答案 0 :(得分:0)

  

在此类中,有一个委托方法,其他两个调用   View Controllers,这些VC之一是弹出窗口,另一个是   普通的VC。

     

委托方法从数据库中获取一些数据,然后进行更新   集合视图在闭包内部调用:   self.artworkCollectionView.reloadData()

  1. 流程似乎是您的VC包含上面的代码,该VC可以打开弹出窗口,也可以只对“普通VC”进行标准的推送。
  2. 您希望在弹出式VC或普通VC中进行一些操作,加载一些数据,然后在将用户定向回原始VC时,UICollectionView会用该数据更新。
  3. li>

您的问题如下:

  

我通过override将artworkCollectionView传递给了普通的VC   performSegue,然后将其作为委托的参数传递回去   方法。这不会给我致命错误,但也不会给我致命错误   重新加载UICollectionView,因为我认为无论如何弱   对UICollectionView出口的引用丢失。   除非您有充分的理由这样做,否则在大多数情况下,您不应该像这样传递任何东西(我看不到)。

您想在这里分开关注。您必须仔细考虑要在VC之间传递的内容,以避免在它们之间产生怪异的依赖关系。我不会通过插座的原因有很多,首先是,如果您决定更改插座,那么现在必须跟踪多个VC中的插座。第二个原因是它需要太多的精神体操来跟踪插座的状态,因为它在各处无处不在。还只能保证将插座设置在生命周期的某些阶段。例如,如果您从prepareForSegue:sender:中的序列中检索目标VC并尝试在此时引用出口,则它们将全部为零,因为尚未设置它们。

这些都是很好的理由,为什么包含以上代码的VC应该是(也是唯一一个)对artworkCollectionView中显示的内容和时间进行控制的人。这里的问题是您如何解决此问题,而不是让弹出窗口或普通VC调用委托方法,或者做一些奇怪的事情,例如将插座从一个VC传递到另一个VC,而只是传递数据。

最简单的示例是:

  1. 弹出式VC和普通VC调用一些代码以实际获取 数据。
  2. 然后根据您实际如何配置弹出式VC或 原始VC的普通VC,请使用parentViewControllerpresentingViewController获取对原始VC的引用。
  3. 通过该引用将数据设置为原始VC。
  4. 如有必要,关闭弹出式VC或普通VC(取决于您的特定应用,也许您希望用户按下UIButton来关闭而不是为他们这样做)。
  5. 当原始的VC重新出现时,将一些代码添加到生命周期方法中,例如 viewWillAppear使其将数据内容加载到 当时UICollectionView

我认为没有理由为什么要在原始VC之外传递任何出口,而这些出口应该是管理它的那个。

答案 1 :(得分:0)

简短的回答:不要那样做。您应该将视图控制器的视图视为私有。您应该在视图控制器中添加一个方法,其他对象会调用该方法来告诉它重新加载其集合视图。

更长的答案是,只要视图控制器在屏幕上,视图控制器的集合视图就应该保留。听起来您对对象生命周期以及ARC的工作原理没有很深入的了解。您应该阅读并做一些练习,直到您对它有所了解为止。

尝试这样的事情:

//Make artworkCollectionView a normal weak var, not implicitly unwrapped. 
//You'll need to change your other code to unwrap it every time you use it.

@IBOutlet weak var artworkCollectionView: UICollectionView?

...

func reloadCollections() {

    retrieveAlbumRatings { (isAlbum) in
        if isAlbum {
            //The construct `[weak self]` below is called a capture list
            self.retrieveAlbumData(completion: { [weak self] (isFinished) in
                guard let weakSelf = self else {
                    print("self is nil");
                    return
                }
            }
            if isFinished {
                // Reload collection views
                guard let collectionView = weakSelf.artworkCollectionView else {
                    print("collectionView is nil!")
                    return
                }
                collectionView.reloadData()
            })
        }
    }
}