UIView 类中的 CollectionView IBOutlet 返回 nil - 只是有时?

Posted

技术标签:

【中文标题】UIView 类中的 CollectionView IBOutlet 返回 nil - 只是有时?【英文标题】:CollectionView IBOutlet inside a UIView class is returning nil - only sometimes? 【发布时间】:2018-06-12 16:59:27 【问题描述】:

因此,我正在尝试寻找新的方法来保持我的项目整洁,并让我自己更容易管理。

我希望这样做的方式是将所有关系都保存在它自己的 swift 文件中,然后在需要时调用它。

我会尽力安排我的问题,但如果屏幕截图有帮助,或者如果您需要任何其他信息,我会尽力提供。

需要注意的一点:应用程序首次启动时会加载集合视图,这是应该的。并且 MenuActionLabel.text 出口,设置为:'Hi'。

但是当我尝试调用 ShowMe() 时,CollectionView 没有重新加载,而是崩溃了,因为 Collectioner 返回了 nil optional。

import UIKit

class UserMenu: UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout 

    struct Variables 
        static var myName = "Hi"
    

    @IBOutlet weak var Collectioner: UICollectionView!

当我调用以下“ShowMe()”函数时,我得到了“coll: nil”的打印结果。

我从 ViewController.swift 调用函数,通过 'UserMenu().ShowMe()'

    func ShowMe() 
        Variables.myName = "Justin"
        print("coll: \(self.Collectioner)")
        //Collectioner.reloadData()
        //^---- causes error - see didSelectItem for my problem...
        //returns nil optional...? Why?
    

    //testing to find errors
    func numberOfSections(in collectionView: UICollectionView) -> Int 
        if collectionView == Collectioner 
            return 1
         else 
            return 0
        
    

    //testing to find errors
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
            if collectionView == Collectioner 
                return 1
             else 
                return 0
            
        

    //testing to find errors
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        if collectionView == Collectioner 
            let Cell:UserMenuCell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath) as! UserMenuCell
            Cell.MenuActionLabel.text = "\(Variables.myName)"
            return Cell
         else 
            let Cell:UserMenuCell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath) as! UserMenuCell
            return Cell
        
    

    //testing to find errors
    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) 
        cell.alpha = 0
        UIView.animate(withDuration: 0.8) 
            cell.alpha = 1
        
    

    //testing to find errors
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
        if collectionView == Collectioner 
            return CGSize(width: Collectioner.frame.width, height: 50)
         else 
            return CGSize(width: Collectioner.frame.width, height: 50)
        
    

    //testing to find errors
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
        if collectionView == Collectioner 
            return 0
         else 
            return 0
        
    

我的困惑出现在这里:

    /*
    When I tap on the cell:
    1. The collection view reloads, and the updated data is shown.

    2. Yet... if I call reloadData from elsewhere,
       the Collectioner outlet returns as an optional nil?
    */

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
        if collectionView == Collectioner 
            print(collectionView)
            print(" ")
            print(Collectioner)
            print(" ")
            collectionView.reloadData()
        
    


didSelectItemAt 的打印输出是:

<UICollectionView: 0x7fd13103a000; frame = (0 0; 314 716); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x60c000242a00>; layer = <CALayer: 0x60c00022d140>; contentOffset: 0, 0; contentSize: 314, 50; adjustedContentInset: 0, 0, 0, 0> collection view layout: <UICollectionViewFlowLayout: 0x7fd12ef1b450>

some(<UICollectionView: 0x7fd13103a000; frame = (0 0; 314 716); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x60c000242a00>; layer = <CALayer: 0x60c00022d140>; contentOffset: 0, 0; contentSize: 314, 50; adjustedContentInset: 0, 0, 0, 0> collection view layout: <UICollectionViewFlowLayout: 0x7fd12ef1b450>)

并且集合视图闪烁,表示它已重新加载。

那么,当我尝试从其他任何地方重新加载集合视图时,为什么它返回 nil?

请帮忙。这让我疯狂。我已经尝试了所有我能想到的方法,并且为寻找答案、解决方案做了很多工作,并且乐于接受建议和学习。

我不确定是否需要在启动时以某种方式“确认”IBOutlet,即使一切似乎都通过 StoryBoard 正确连接。

编辑 - ViewController.swift:

import UIKit

class ViewController: UIViewController 

    let userMenu = UserMenu()

    override func viewDidLoad() 
        super.viewDidLoad()
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
    

    @IBOutlet weak var button: UIButton!
    @IBAction func button(_ sender: Any) 
        print("Tapped Button")
        UserMenu().ShowMe()
    


编辑 - Heirachy

干杯,

贾斯汀。

【问题讨论】:

【参考方案1】:

谈谈当你打电话给UserMenu().ShowMe()时会发生什么

首先调用UserMenu()并使用init()方法初始化一个新的UserMenu实例。 其次,这个实例会调用ShowMe()方法。

为什么会崩溃? - 因为UserMenu 实例默认初始化init 方法并且没有从Storyboard 加载任何内容。当然,在这种情况下,Collectioner 将是nil,它会导致崩溃。

要修复它,您应该将UserMenu 实例作为属性保留在ViewControler 中(可以将其命名为userMenu)。每次要调用ShowMe()方法,都应该是userMenu.ShowMe()

编辑:将用户菜单视图从 Storyboard 连接到 @IBOutlet weak var userMenu: UserMenu!,并在下面使用我的代码。

class ViewController: UIViewController 

  @IBOutlet weak var userMenu: UserMenu!

  override func viewDidLoad() 
    super.viewDidLoad()
  

  override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
  

  @IBOutlet weak var button: UIButton!
  @IBAction func button(_ sender: Any) 
    print("Tapped Button")
    userMenu.ShowMe()
  

【讨论】:

我很困惑。我没有在任何地方使用过 init() 吗?此外,如果我从 ViewController.swifts 的 viewDidLoad() 调用 UserMenu().ShowMe() - 它会打印出“Justin”。那么,如果一切都已连接,为什么它不重新加载 collectionView 呢?如果我遗漏了什么,我真的很感激一些帮助。 UserMenu() 等于 UserMenu.init()。我认为这就是你所缺少的。 实际上我需要在viewDidLoad 中查看您的代码才能知道它发生的原因。也许您应该在 viewDidLoad 和创建 UserMenu 的位置添加所有代码 当你调用 UserMenu().ShowMe() 时,ShowMe() 方法被调用并打印出“Justin”。但是此时Collectionernil,因为UserMenu是使用init()方法初始化的,会导致crash 所以我在ViewController.swift中从viewDidLoad调用UserMenu(),和UserMenu.init()基本一样...?另外,您的问题的编辑是我的 ViewController 是如何设置的,但是,我得到的唯一错误是我的 Collecioner 出口为零,即使它在单元设置期间注册为 collectionView == Collectioner 等。好的,将添加 ViewController代码。感谢您的帮助!

以上是关于UIView 类中的 CollectionView IBOutlet 返回 nil - 只是有时?的主要内容,如果未能解决你的问题,请参考以下文章

方法没有覆盖超类中的任何函数(覆盖 func collectionView)[重复]

带有 TableView 和 CollectionView 的 UiView 不会随机刷新

如果collectionView低于某些uiview,iOS如何使collectionView接收触摸

Swift 中带有 CollectionView 和 TableView 的 UIView

在带有 xib 文件的 UIView 中使用 CollectionView

更改 CollectionView 单元内的 UIView 宽度