UIView子类中的self.removeFromSuperview()

时间:2016-08-03 22:04:13

标签: ios swift uiview

上下文 我创建了一个UIView(helloView)的子类来显示一些文本和一个位于MainViewController视图顶部的按钮。 此子类在MainVC viewDidLoad中初始化并添加到视图中:view.addSubview(helloView)

目标:helloView有一个目标为dimissHelloView的UIButton(continueButton)。此方法只需调用self.removeFromSuperView(),以便在屏幕上轻松获取helloView。

问题:用户与按钮的交互会破坏代码并返回nil指针异常(在解包Optional值时意外地发现nil)。尽管在SO和Google上搜索了几个小时,但我找不到通过自己的按钮子视图解除视图的正确方法。

以前的疑难解答:调用removeFromSuperview时,superview似乎是nil,但如果我使用断点并在控制台中调用它,则不是。

代码:忽略属性和约束片段,按钮创建和目标操作位于底部。

import UIKit

class HelloView: UIView {

    var helloText: String = ""
    var continueButton: UIButton!

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

        didLoad()
    }

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

        didLoad()
    }

    func didLoad(){

        self.translatesAutoresizingMaskIntoConstraints = false
        setContinueButton()
        self.addSubview(continueButton)
    }

    override func didMoveToSuperview() {
        setConstraints()
    }

    func setConstraints(){

        //remove any previous constraints
        for constraint in superview!.constraints {
            if constraint.firstItem as! UIView == self && constraint.secondItem as? UIView == superview {
                superview!.removeConstraint(constraint)
            }
        }

        // Hello View basic constraints
        let xAxisConstraint = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1, constant: 0)
        let yAxisConstraint = NSLayoutConstraint(item: self, attribute: .CenterY, relatedBy: .Equal, toItem: superview, attribute: .CenterY, multiplier: 1, constant: 0)

        // check device orientation and add constraints consequently
        if UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation) {
            let widthConstraint = NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: superview, attribute: .Width, multiplier: 1, constant: -100)
            let heightConstraint = NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: superview, attribute: .Height, multiplier: 1, constant: -150)
            superview!.addConstraints([xAxisConstraint, yAxisConstraint, widthConstraint, heightConstraint])
        }
        if UIDeviceOrientationIsPortrait(UIDevice.currentDevice().orientation){
            let widthConstraint = NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: superview, attribute: .Width, multiplier: 1, constant: -100)
            let heightConstraint = NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: superview, attribute: .Height, multiplier: 1, constant: -300)
            superview!.addConstraints([xAxisConstraint, yAxisConstraint, widthConstraint, heightConstraint])
        }

        // Continue Button constraints
        let centerXConstraint = NSLayoutConstraint(item: continueButton, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .CenterX, multiplier: 1, constant: 0)
        let bottomConstraint = NSLayoutConstraint(item: continueButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -8)
        self.addConstraints([centerXConstraint, bottomConstraint])
    }

    func setContinueButton(){
        continueButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
        continueButton.setTitle("Continue", forState: .Normal)
        continueButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        continueButton.addTarget(self, action: #selector(HelloView.dismissHelloView), forControlEvents: .TouchUpInside)
        continueButton.translatesAutoresizingMaskIntoConstraints = false
    }

    func dismissHelloView(){
        print(superview!)
        self.removeFromSuperview()
    }

}

1 个答案:

答案 0 :(得分:0)

当您从超级视图中删除视图时,didMoveToSuperview将被调用(超级视图将为nil)。您的setConstraints函数是从didMoveToSuperview调用的,它会强行展开superview,这是零,导致崩溃。可选项的全部意义在于它会强制您考虑如果某些事情为零,会发生什么。

无论如何,在你的情况下,当superview变为零时,你不希望发生任何事情,所以我在didMoveToSuperview的顶部放了这样的东西:

guard superview != nil else { return }