我正试图从UIView中启用或禁用工具栏的@IBOutlet UIButton项。
当我在EraseView.Swift中使用的数组为空时,该按钮应该被禁用。
我试图创建视图控制器的实例,但它给了我一个错误(在展开时发现为零):
在橡皮擦视图中:
class EraseView: UIView {
...
let editViewController = EditImageViewController()
//array has item
editViewController.undoEraseButton.enabled = true //here I get the error
...
}
我试图在EditImageViewController中放置一个全局Bool,该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
...
}
我知道这很简单,但我不能让它起作用。情况是这样的:
最佳答案
问题的根源是这样一句话:
let editViewController = EditImageViewController()
EditImageViewController()
表示“忽略故事板已经为我实例化的内容,而是实例化另一个没有连接插座的视图控制器并使用它。”显然,这不是您想要的。您需要为
EraseView
提供某种方式通知现有的视图控制器是否对其“空”状态有所更改。而且,理想情况下,您希望以保持这两个类松散耦合的方式执行此操作。EraseView
只应通知视图控制器“is empty”状态的更改,视图控制器应启动其他子视图(即按钮)的更新。一个视图不应该更新另一个视图的出口。有两种方法可以做到这一点:
关闭:
您可以给
EraseView
一个可选的闭包,当它从“empty”和“notempty”切换时,它将调用这个闭包: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
adelegate
属性:weak var delegate: EraseViewDelegate?
注意,这是
weak
以避免强引用循环。(这也是我将协议定义为class
协议的原因,因此我可以在这里将其设置为weak
。)当视图的“is empty”状态更改时,
EraseView
将调用此委托。例如,当它变为空时,它会相应地通知其代理:delegate?.eraseViewIsEmpty(true)
然后,同样地,为了使这一切正常工作,视图控制器应该(a)声明它符合协议;(b)指定自己为
delegate
的EraseView
;和(c)实现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
}
}
这两种模式都保持了两个类的松散耦合,但允许
EraseView
将某些事件通知其视图控制器。它还消除了任何全球性的需求。也有其他方法可以解决这个问题(例如通知、KVN等),但希望这说明了基本思想。视图应将任何关键事件通知其视图控制器,视图控制器应负责更新其他视图。
关于swift - 从 subview 更改@IBOutlet,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37077615/