我正在尝试从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
...
}
答案 0 :(得分:1)
问题的根源是:
let editViewController = EditImageViewController()
EditImageViewController()
说"忽略故事板已经为我实例化的内容,而是实例化另一个视图控制器,没有连接出口并使用它。"显然,这不是你想要的。
你需要为EraseView
提供一些方法来通知现有的视图控制器是否有一些变化,它是空的"州。理想情况下,您希望以保持这两个类松散耦合的方式执行此操作。 EraseView
应该只通知视图控制器"是空的"状态,视图控制器应启动其他子视图(即按钮)的更新。一个视图真的不应该更新另一个视图的出口。
有两种方法可以做到这一点:
<强>封闭强>:
你可以给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
来避免强参考周期。
委托协议模式:
所以你可以定义一个协议来做到这一点:
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
这两种模式都使两个类松散耦合,但允许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等),但希望这说明了基本的想法。视图应通知其视图控制器任何关键事件,视图控制器应负责更新其他视图。