使用具有通用数据类型的协议在屏幕之间传递数据
Using protocol with generic data type to pass data between screens
我是 Android 开始学习的开发者 iOS。我正在尝试在主从样式应用程序之间传递数据。
我得到了 controller1
,其中包含 ToDo
项列表,controller2
允许创建新的 ToDo
项并将其添加到 controller1
的列表中。
我创建了一个协议:
protocol ListDataHolder {
associatedtype T
func addItem(item: T)
func reloadData()
}
在 controller1
的 prepare
中分配了 self
:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller2 = segue.destination as? Controller2{
controller2.toDoDataHolder = self
}
}
在 controller2
中声明委托
// how do I tell to use ToDo class for generic type here
var toDoDataHolder: ListDataHolder? = nil
并像这样使用它:
@IBAction func onAddClicked(_ sender: Any) {
let toDo = ToDo()
...
toDoDataHolder?.addItem(item: toDo)
toDoDataHolder?.reloadData()
navigationController?.popViewController(animated: true)
}
这样做时我遇到了一些错误:
对于委托声明:
Protocol 'ListDataHolder' can only be used as a generic constraint because it has Self or associated type requirements
使用addItem()
时:
Cannot convert value of type 'ToDo' to expected argument type 'ListDataHolder.T'
Insert ' as! ListDataHolder.T'
Member 'addItem' cannot be used on value of protocol type 'ListDataHolder'; use a generic constraint instead
当我从协议中删除泛型而只有 addItem(item: ToDo)
时,一切正常。但我希望能够将 ListDataHolder
与任何数据类型一起使用。
这只是我的实验,我并不是在寻找在控制器之间传递数据的正确方法。
编辑:您可以在此 GitHub 存储库中找到完整代码:github.com/Sermilion/ios_learning
如果您总是将 ToDo
实例传递给 addItem
方法,请使用 ToDo
而不是在 ListDataHolder
协议中使用关联类型。
如果您需要此协议 addItem
方法将适用于任何通用类型,请使用以下代码。
protocol ListDataHolder {
func addItem<T:Decodable>(item: T)
func reloadData()
}
struct ToDo: Decodable {
}
class A: ListDataHolder {
func addItem<T:Decodable>(item: T) {
print("Add Item called")
}
func reloadData(){
}
}
这里需要实现委托设计模式。
请详细查看委托设计模式。
您需要做的是使第二个视图控制器使用协议 和 来限制 class 使用(或持有)的对象类型符合ListDataHolder
这可以在视图控制器的声明中完成
class SecondViewController<Holder: ListDataHolder>: UIViewController where Holder.T == ToDo
那么您的方法 onAddClicked
将按原样工作。
我是 Android 开始学习的开发者 iOS。我正在尝试在主从样式应用程序之间传递数据。
我得到了 controller1
,其中包含 ToDo
项列表,controller2
允许创建新的 ToDo
项并将其添加到 controller1
的列表中。
我创建了一个协议:
protocol ListDataHolder {
associatedtype T
func addItem(item: T)
func reloadData()
}
在 controller1
的 prepare
中分配了 self
:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller2 = segue.destination as? Controller2{
controller2.toDoDataHolder = self
}
}
在 controller2
// how do I tell to use ToDo class for generic type here
var toDoDataHolder: ListDataHolder? = nil
并像这样使用它:
@IBAction func onAddClicked(_ sender: Any) {
let toDo = ToDo()
...
toDoDataHolder?.addItem(item: toDo)
toDoDataHolder?.reloadData()
navigationController?.popViewController(animated: true)
}
这样做时我遇到了一些错误:
对于委托声明:
Protocol 'ListDataHolder' can only be used as a generic constraint because it has Self or associated type requirements
使用addItem()
时:
Cannot convert value of type 'ToDo' to expected argument type 'ListDataHolder.T'
Insert ' as! ListDataHolder.T'
Member 'addItem' cannot be used on value of protocol type 'ListDataHolder'; use a generic constraint instead
当我从协议中删除泛型而只有 addItem(item: ToDo)
时,一切正常。但我希望能够将 ListDataHolder
与任何数据类型一起使用。
这只是我的实验,我并不是在寻找在控制器之间传递数据的正确方法。
编辑:您可以在此 GitHub 存储库中找到完整代码:github.com/Sermilion/ios_learning
如果您总是将 ToDo
实例传递给 addItem
方法,请使用 ToDo
而不是在 ListDataHolder
协议中使用关联类型。
如果您需要此协议 addItem
方法将适用于任何通用类型,请使用以下代码。
protocol ListDataHolder {
func addItem<T:Decodable>(item: T)
func reloadData()
}
struct ToDo: Decodable {
}
class A: ListDataHolder {
func addItem<T:Decodable>(item: T) {
print("Add Item called")
}
func reloadData(){
}
}
这里需要实现委托设计模式。 请详细查看委托设计模式。
您需要做的是使第二个视图控制器使用协议 和 来限制 class 使用(或持有)的对象类型符合ListDataHolder
这可以在视图控制器的声明中完成
class SecondViewController<Holder: ListDataHolder>: UIViewController where Holder.T == ToDo
那么您的方法 onAddClicked
将按原样工作。