【问题标题】:IBoutlet Connected From SuperClass UIView Still Nil从 SuperClass UIView 连接的 IBoutlet 仍然为零
【发布时间】:2018-03-18 22:00:25
【问题描述】:

我与 Nibs 合作。我有两个屏幕将使用具有相同行为的“相同”UIView 组件。它不是同一个组件,因为在每个屏幕中我都放置了一个 UIView 并进行了相同的配置,如图所示。

为了解决这个问题并防止在其他类中复制相同的代码,我编写了一个类,即UIView 子类,具有我需要的所有功能。

之后我将我的自定义类作为这些UIView 组件的超类来继承IBOutlets 和所有功能。

我的自定义类没有在Nib 中定义,只是.swift 类。

我建立了所有必要的连接,但在运行时IBOutletsNil

我的自定义类的代码:

class FeelingGuideView: UIView {

    @IBOutlet weak var firstScreen: UILabel!
    @IBOutlet weak var secondScreen: UILabel!
    @IBOutlet weak var thirdScreen: UILabel!
    @IBOutlet weak var fourthScreen: UILabel!

    private var labelsToManage: [UILabel] = []
    private var willShow: Int!
    private var didShow: Int!

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.initLabelManagement()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.initLabelManagement()
    }

    private func initLabelManagement() {
        self.initLabelVector()
        self.willShow = 0
        self.didShow = 0
        self.setupLabelToShow(label: labelsToManage[0])
        self.setupLabels()
    }

    private func initLabelVector() {
        self.labelsToManage.append(self.firstScreen)
        self.labelsToManage.append(self.secondScreen)
        self.labelsToManage.append(self.thirdScreen)
        self.labelsToManage.append(self.fourthScreen)
    }

    private func setupLabels() {

        for label in labelsToManage {
            label.layer.borderWidth = 2.0
            label.layer.borderColor = UIColor(hex: "1A8BFB").cgColor
        }
    }

    func willShowFeelCell(at index: Int) {
        self.willShow = index

        if willShow > didShow {
            self.setupLabelToShow(label: labelsToManage[willShow])
        }
        else if willShow < didShow {

            for i in didShow ... willShow + 1 {

                let label = labelsToManage[i]
                self.setupLabelToHide(label: label)
            }
        }
    }

    private func setupLabelToShow(label: UILabel) {
        label.textColor = UIColor.white
        label.backgroundColor = UIColor(hex: "1A8BFB")
    }

    private func setupLabelToHide(label: UILabel) {
        label.textColor = UIColor(hex: "1A8BFB")
        label.backgroundColor = UIColor.white
    }
}

我发现这个问题与我的类似:Custom UIView from nib inside another UIViewController's nib - IBOutlets are nil

但我的UIView 不在笔尖中。

编辑:

我覆盖了awakeFromNib,但它没有进入方法。

更多解释:

我的自定义类只是这个组件的超类:

我在两个屏幕上复制。

一个屏幕是UITableViewCell,另一个是UIViewController

将根据UICollectionView 上当前显示的屏幕来管理标签的行为

当在required init?(coder aDecoder:) 处调用initLabelVector() 函数时,会出现解包错误:

尝试打开View时的错误:

UITableViewCell 无法显示错误,因为它在应用程序的开头被调用并且不显示任何内容。为了在屏幕上显示错误,我需要删除UITableViewCell 的调用。

UITableViewCell 首先使用tableView.register(nib:) 注册,然后使用tableView.dequeueReusebleCell

UIViewController 是从菜单类中调用的:

startNavigation = UINavigationController(rootViewController: FellingScreenViewController())
appDelegate.centerContainer?.setCenterView(startNavigation, withCloseAnimation: true, completion: nil)

【问题讨论】:

  • 也许init(coder:) 太早了:视图存在,但它的出口尚未连接。尝试在稍后初始化之前不要访问视图出口,例如覆盖willMove(toWindow:)didMoveToWindow。此外,我认为您声称 awakeFromNib 没有被称为令人深感不安,因为那是我会尝试的初始化时刻。
  • 非常感谢!这正是问题所在。在 init 中,出口尚未连接。我在viewDidLoad() 的父类上调用了initLabelManagement() 函数并工作了。谢谢!

标签: ios swift xcode iboutlet


【解决方案1】:

问题是这段代码:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.initLabelManagement()
}

问题在于init(coder:)为时过早 来谈论视图的出口,这就是initLabelManagement 所做的;插座还没有连接。改为:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
override func awakeFromNib() {
    super.awakeFromNib()
    self.initLabelManagement()
}

我是如何得出这个答案的:

作为测试,我尝试了这个:

class MyView : UIView {
    @IBOutlet var mySubview : UIView!
    required init?(coder aDecoder: NSCoder) {
        super.init(coder:aDecoder)
        print(#function, self.mySubview)
    }
    override func awakeFromNib() {
        super.awakeFromNib()
        print(#function, self.mySubview)
    }
}

这是输出:

init(coder:) nil
awakeFromNib() <UIView: 0x7fc17ef05b70 ... >

这证明了什么:

  • init(coder:)为时过早;插座还没有接上

  • awakeFromNib不会太快了;插座 已连接

  • awakeFromNib 被称为,尽管你声称相反

【讨论】:

  • setupLabels()(来自initLabelManagement() 的消息)也适用于该层,可能尚未在awakeFromNib() 计算该帧。这不应该在layoutSubviews() 或类似的地方完成吗?
  • @AlejandroIván 我不关心这个。当谈到init(coder:) 中的插座属性时,OP 询问为什么会出现“nil 展开可选”错误,我回答了这个问题。此处采用的整个方法的可取性超出了本次讨论的范围。
【解决方案2】:

当我的自定义类中的init() 被调用时,IBOutlets 尚未连接。

所以,我在父视图上创建了一个引用,并从 viewDidLoad() 方法中调用了 iniLabelManagement(),一切正常。

感谢马特的帮助和耐心!

【讨论】:

  • 很好,当然你现在已经违反了视图类的封装。最好弄清楚视图本身何时可以保证其插座已连接。这正是我认为awakeFromNib 的样子。
  • 谢谢,我会试试的。当我这样做时,我会最终给出答案。
  • 我添加了一个答案,证明应该调用 awakeFromNib 并且现在是开始谈论视图的出口的正确时机。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多