2016-05-06 2 views
1

Я пытаюсь включить или отключить элемент UIButton @IBOutlet из панели UIView.
Кнопка должна быть отключена, когда массив, который я использую в EraseView.Swift, пуст.
Я попытался создать экземпляр контроллера представления, но он дает мне ошибку (находится ноль, а разворачивание):
в EraseView:Изменить @IBOutlet из подвью

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

Я пытался поставить глобальную Bool, который изменил значение с помощью это в EditImageViewController, но он не работает:

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

Корень проблемы является линией, которая говорит:

let editViewController = EditImageViewController() 

EditImageViewController() говорит «игнорировать то, что раскадровка уже инстанцирована для меня, а экземпляр другого вида контроллер, который не подключен к розеткам и не использует это ». Понятно, что это не то, что вы хотите.

Необходимо указать способ для EraseView, чтобы сообщить существующему контроллеру представления о том, было ли какое-то изменение его «пустым». И, в идеале, вы хотите сделать это таким образом, чтобы эти два класса не были связаны друг с другом. EraseView должен только информировать диспетчер представлений об изменении состояния «пусто», а контроллер просмотра должен инициировать обновление других подзонов (т. Е. Кнопки). В представлении действительно не должно обновляться выходы другого вида.

Есть два способа вы можете сделать это:

  1. Закрытие:

    Вы можете дать опциональное закрытие EraseView, что он будет звонить, когда он переключается с «пустым» и «не пустой ":

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

    Затем дать EraseViewdelegate свойство:

    weak var delegate: EraseViewDelegate? 
    

    Примечание, это weak, чтобы избежать сильных эталонных циклов. (И это также, почему я определил протокол быть class протокол, так что я мог бы сделать это weak здесь.)

    The EraseView затем называют этот делегат, когда «пусто» изменения состояния представления. Например, когда он становится пустым, он будет информировать его делегат соответственно:

    delegate?.eraseViewIsEmpty(true) 
    

    Тогда, опять же, за все это работать, контроллер вид должен (а) заявить, что это соответствует протоколу; (b) указать себя как delegate из 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 
        } 
    } 
    

Обе эти модели держать два класса слабосвязанные, но позволяют EraseView сообщить свой вид контроллер какого-либо события. Это также устраняет необходимость в любом глобальном.

Существуют и другие подходы, которые могут решить эту проблему (например, уведомления, KVN и т. Д.), Но, надеюсь, это иллюстрирует основную идею. Представления должны сообщать контроллеру своего представления о любых ключевых событиях, а диспетчер представлений должен следить за обновлением других представлений.

Смежные вопросы