Что я делаю не так при передаче данных по протоколу

#ios #swift #protocols

#iOS #swift #протоколы

Вопрос:

Я пытаюсь передать данные между ViewControllers, но что-то кажется неправильным.

В первом ViewController я хочу установить «Bool» для функции протокола, чтобы иметь возможность восстанавливаться на другом экране. Что я делаю не так, я всегда использовал протоколы, но на этот раз у меня возникли проблемы.

Вот как я это делаю:

 //
//  ComboBoxNode.swift
//

import Foundation
import SWXMLHash


protocol ComboBoxNodeDelegate {
    func getCustomOption(data:Bool)
}

class ComboBoxNode: FormControlNode, IFormControlDataSource {


    var listType: String?
    var dataSource: String?
    var dataSourceValue: String?
    var dataSourceText: String?
    var hasCustomOption:Bool?
    var customOptionText: String?
    var ctrlDataSourceType: String?
    var parameters = [ParameterNode]()
    var staticList: FormControlStaticListNode?

    var delegate:ComboBoxNodeDelegate?

    override init(indexer: XMLIndexer) {
        super.init(indexer: indexer)

        guard let element = indexer.element else {
            preconditionFailure("Error")
        }


        let isCustomOption = element.bool(by: .hasCustomOption) ?? hasCustomOption

        if isCustomOption == true {
            self.delegate?.getCustomOption(data: hasCustomOption!)
        }


        self.readFormControlDataSource(indexer: indexer)
    }

    override func accept<T, E: IViewVisitor>(visitor: E) -> T where E.T == T {
        return visitor.visit(node: self)
    }
}
  

Вот как я пытаюсь восстановить на следующем экране:

 //  FormPickerViewDelegate.swift

import Foundation
import ViewLib
import RxSwift

class FormPickerViewDelegate: NSObject {

    var items = Variable([(value: AnyHashable, text: String)]()) {
        didSet {
            PickerNodeDelegate = self
            self.setDefaultValues()
        }
    }

    private var controlViewModel: FormControlViewModel
    private var customText:Bool?

    private var PickerNodeDelegate:ComboBoxNodeDelegate?

    init(controlViewModel: FormControlViewModel) {
        self.controlViewModel = controlViewModel
    }

    func getItemByValue(_ value: Any) -> (AnyHashable, String)? {

        if value is AnyHashable {
            let found = items.value.filter {$0.value == value as! AnyHashable}
            if found.count >= 1 {
                return found[0]
            }
        }

        return nil
    }
}


extension FormPickerViewDelegate:ComboBoxNodeDelegate {
    func getCustomOption(data: Bool) {
        customText = data
    }
}
  

Комментарии:

1. Я думаю, вы просто ссылаетесь PickerNodeDelegate на себя, и ваш FormPickerViewDelegate класс не соответствует ComboBoxNodeDelegate протоколу.

2. Можете ли вы подсказать мне, где я должен отредактировать?

3. delegate Свойство в ComboBoxNode никоим образом не может иметь значение в init , поскольку делегат не задан в init , и вы не можете ссылаться на объект из какого-либо другого места, пока init не будет завершено. В FormPickerViewDelegate вы устанавливаете его PickerNodeDelegate для себя и в любом случае никогда не вызываете функцию делегата.

4. Если вы просто хотите передать свойство с одного экрана на другой, вам, вероятно, не нужен шаблон делегирования. Я действительно не могу сказать вам, что нужно изменить, потому что взаимосвязь между двумя показанными классами неясна.

5. Что, если я использую статический var для попытки сохранения?

Ответ №1:

Вместо установки PickerNodeDelegate = self в didSet {} закрытии

    var items = Variable([(value: AnyHashable, text: String)]()) {
        didSet {
            PickerNodeDelegate = self
            self.setDefaultValues()
        }
    }

  

Вместо этого назначьте его в вашей функции init()

     init(controlViewModel: FormControlViewModel) {
        self.controlViewModel = controlViewModel
        PickerNodeDelegate = self
    }
  

Обратите внимание, что ваш делегат должен быть weak также, поскольку это делегат, ваш протокол должен соответствовать типу класса, чтобы быть ослабленным.

 protocol ComboBoxNodeDelegate: class
...
weak var delegate: ComboBoxNodeDelegate?
  

Комментарии:

1. Вы не сможете объявить delegate as weak , если не привязаете протокол к классу.

Ответ №2:

Вот пример, надеюсь, это поможет!

 protocol ComboBoxNodeDelegate {
    func getCustomOption(data:Bool) -> String 
}

class ViewOne:ComboBoxNodeDelegate {
    var foo:Bool = false
    var bar:String = "it works!"

    /** Return: String */
    func getCustomOption(data:Bool) -> String { //conform here to protocol
          // do whatever you wanna do here ...example
          self.foo = data // you can set
          return bar // even return what you want

    }

    //initialize
    func initalizeViewTwo() {
         let v2 = ViewTwo()
         v2.delegate = self //since `self` conforms to the ComboBoxNodeDelegate protcol you are allowed to set
    }


}

class ViewTwo { 
    var delegate:ComboBoxNodeDelegate?

    func getCustomOption_forV1() {
        let view2_foo = delegate.getCustomOption(data:true)
        print(view2_foo) // should print "it works!"
    } 
}
  

Комментарии:

1. Да, поэтому, если вы хотите, чтобы ViewTwo получал некоторые данные, вы можете сделать это следующим образом. ^^^ (Я обновлю код)

Ответ №3:

Все параметры, передаваемые в Swift, являются константами, поэтому вы не можете их изменить.

Если вы хотите изменить их в функции, вы должны объявить свой протокол для передачи по ссылке с inout :

 protocol ComboBoxNodeDelegate {
    func getCustomOption(data: inout Bool)
}
  

Примечание: вы не можете передать константу (let) этой функции. Это должна быть переменная — что, я вижу, вы и делаете!