#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
asweak
, если не привязаете протокол к классу.
Ответ №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) этой функции. Это должна быть переменная — что, я вижу, вы и делаете!