我正试图从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
    ...
}

我知道这很简单,但我不能让它起作用。情况是这样的:
swift - 从 subview 更改@IBOutlet-LMLPHP

最佳答案

问题的根源是这样一句话:

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)
}

然后给出EraseViewadelegate属性:
weak var delegate: EraseViewDelegate?

注意,这是weak以避免强引用循环。(这也是我将协议定义为class协议的原因,因此我可以在这里将其设置为weak。)
当视图的“is empty”状态更改时,EraseView将调用此委托。例如,当它变为空时,它会相应地通知其代理:
delegate?.eraseViewIsEmpty(true)

然后,同样地,为了使这一切正常工作,视图控制器应该(a)声明它符合协议;(b)指定自己为delegateEraseView;和(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/

10-11 14:42