从子视图

时间:2016-05-06 16:49:59

标签: swift iboutlet

我正在尝试从UIView启用或禁用工具栏的@IBOutlet UIButton项。
当我在EraseView.Swift中使用的数组为空时,按钮应该被禁用
我尝试创建一个视图控制器的实例,但它给了我错误(在解包时找到了nil):
在EraseView中:

class EraseView: UIView {
    ...
    let editViewController = EditImageViewController()
    //array has item
    editViewController.undoEraseButton.enabled = true //here I get the error
    ...
}

我试图在EditImageViewController中使用它来更改值的全局 Bool 但它不起作用:

var enableUndoButton =  false

class EditImageViewController: UIViewController {

   @IBOutlet weak var undoEraseButton: UIBarButtonItem!

    viewDidLoad() {
        undoEraseButton.enabled = enableUndoButton
    }
}

class EraseView: UIView {
    ...        
    //array has item
    enableUndoButton = true //here I get the error
    ...
}

我知道这很简单,但我不能让它发挥作用。
这是情况: enter image description here

1 个答案:

答案 0 :(得分:1)

问题的根源是:

let editViewController = EditImageViewController()

EditImageViewController()说"忽略故事板已经为我实例化的内容,而是实例化另一个视图控制器,没有连接出口并使用它。"显然,这不是你想要的。

你需要为EraseView提供一些方法来通知现有的视图控制器是否有一些变化,它是空的"州。理想情况下,您希望以保持这两个类松散耦合的方式执行此操作。 EraseView应该只通知视图控制器"是空的"状态,视图控制器应启动其他子视图(即按钮)的更新。一个视图真的不应该更新另一个视图的出口。

有两种方法可以做到这一点:

  1. <强>封闭

    你可以给EraseView一个可选的闭包,当它从&#34;空转&#34;并且&#34;不是空的&#34;:

    var emptyStateChanged: ((Bool) -> ())?
    

    然后它可以在状态改变时调用它。例如,当您删除视图中的最后一项时,EraseView可以调用该闭包:

    emptyStateChanged?(true)
    

    最后,为了实际执行任何操作,视图控制器应提供实际的闭包以在状态更改时启用和禁用按钮:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        eraseView.emptyStateChanged = { [unowned self] isEmpty in 
            self.undoEraseButton.enabled = !isEmpty
        }
    }
    

    注意,我使用unowned来避免强参考周期。

  2. 委托协议模式

    所以你可以定义一个协议来做到这一点:

    protocol EraseViewDelegate : class {
        func eraseViewIsEmpty(empty: Bool)
    }
    

    然后给EraseView一个delegate属性:

    weak var delegate: EraseViewDelegate?
    

    请注意,weak可以避免强烈的参考周期。 (这也是为什么我将协议定义为class协议的原因,以便我可以在此处weak进行协商。)

    EraseView会在视图&#34;为空时调用此委托&#34;状态变化。例如,当它变空时,它会相应地通知其代表:

    delegate?.eraseViewIsEmpty(true)
    

    然后,再次,为了这一切工作,视图控制器应该(a)声明符合协议; (b)将自己指定为delegate的{​​{1}}; (c)实施EraseView方法,例如:

    eraseViewIsEmpty
  3. 这两种模式都使两个类松散耦合,但允许class EditImageViewController: UIViewController, EraseViewDelegate { @IBOutlet weak var undoEraseButton: UIBarButtonItem! override func viewDidLoad() { super.viewDidLoad() eraseView.delegate = self } func eraseViewIsEmpty(empty: Bool) { undoEraseButton.enabled = !empty } } 通知其视图控制器某些事件。它还消除了对任何全局的需求。

    还有其他方法可以解决这个问题(例如通知,KVN等),但希望这说明了基本的想法。视图应通知其视图控制器任何关键事件,视图控制器应负责更新其他视图。