本文介绍了通用视图控制器不适用于委托和扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 限时删除!! 我已经发布了问题,但不清楚我想要什么。正如@AlainT建议的那样,我提出了一个新的。 我有一个typealias元组 public typealias MyTuple< T> =(key:T,value:String) 协议: public protocol VCADelegate:class { associatedtype T func didSelectData(_ selectedData:MyTuple< T>)} 具有表格视图的视图控制器(VCA) class VCA< T>:UIViewController,UITableViewDelegate,UITableViewDataSource { $ b $ var dataList = [MyTuple< T>() weak var delegate: VCADelegate? //错误:只能用作通用约束 // ... public func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath){委托?.didSelectData(dataList [indexPath.row])} } 在另一个视图控制器(VCB)中,我创建了一个VCA并通过一个dataList func callVCA(){ let vcA = VCA< String>() vcA.dataList = [(key:1,value:Value 1),(key:2,value:值2)] } 我想要做的是让dataList没有了解VCA中密钥的数据类型。只有当VCB调用VCA时,我才知道密钥的数据类型。创建通用视图控制器会导致代理问题。任何方式来解决这个问题,而不必改变完成关闭? 使用通用视图控制器的另一个问题是我无法扩展它。任何想法?解决方案这是一个标准的类型擦除的情况,虽然在这种情况下我只是通过一个闭包因为只有一种方法)。 创建一个橡皮擦代替协议: public struct AnyVCADelegate< T> { let _didSelectData:(MyTuple< T>) - > Void func didSelectData(_ selectedData:MyTuple< T>){_didSelectData(selectedData)} init< Delegate:VCADelegate>(delegate:Delegate)其中Delegate.T == T { _didSelectData = delegate.didSelectData 使用它代替委托: class VCA< T>:UIViewController,UITableViewDataSource UITableViewDelegate { var dataList = [MyTuple< T> ;]() var delegate:AnyVCADelegate< T> ;? // ... public func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath){ delegate?.didSelectData(dataList [indexPath.row ])} } 您的潜在问题是具有关联类型的协议本身不是合适的类型。他们只是类型限制。如果你想保留一个PAT,那很好,但是你必须在代理上使 VCA 泛型: class VCA< Delegate:VCADelegate> ;: UIViewController,UITableViewDelegate { var dataList = [MyTuple< Delegate.T>]() weak var代表:代表? init(delegate:Delegate?){ self.delegate = delegate super.init(nibName:nil,bundle:nil)} 需要init(coder:NSCoder){super.init(nibName:nil,bundle:nil)} public func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath){委托?.didSelectData(dataList [indexPath.row])} } 类VCB:UIViewController,VCADelegate { func didSelectData( _ selectedData:MyTuple< String>){} func callVCA(){ let vcA = VCA(delegate:self) vcA.dataList = [(key:1 ,值:肉桂),(键:2,值:丁香)] } } pre> 通常,具有关联类型(PAT)的协议是非常强大但特殊用途的工具。它们不是泛型的替代品(这是一个通用工具)。 尽管这个问题可能只是传递了一个闭包。所有类型的橡皮擦(通常)都是一个充满闭合的结构。 (有一天编译器可能会为我们编写它们,这个问题的大部分将会消失,PAT会在日常代码中很有用,但现在它不会。)I already posted a question but it was not clear about what I want. As @AlainT suggested, I filed a new one.I have a typealias tuplepublic typealias MyTuple<T> = (key: T, value: String)A protocol:public protocol VCADelegate: class { associatedtype T func didSelectData(_ selectedData: MyTuple<T>)}A view controller (VCA) with a table viewclass VCA<T>: UIViewController, UITableViewDelegate, UITableViewDataSource { var dataList = [MyTuple<T>]() weak var delegate: VCADelegate? // Error: can only be used as a generic constraint // ... public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { delegate?.didSelectData(dataList[indexPath.row]) }}In another view controller (VCB), I create a VCA and pass through a dataListfunc callVCA() { let vcA = VCA<String>() vcA.dataList = [(key: "1", value:"Value 1"), (key: "2", value:"Value 2")]}What I want to do is to have a dataList without knowing key's data type in VCA. Only when VCB calls VCA then I know the data type of the key. Creating a generic view controller will cause an issue with delegate. Any way to solve this problem without having to change to closure completion?The other issue of using a generic view controller is I can't extend it. Any idea? 解决方案 This is a standard type-erasure situation, though in this particular case I'd just pass a closure (since there's only one method).Create a type eraser instead of a protocol:public struct AnyVCADelegate<T> { let _didSelectData: (MyTuple<T>) -> Void func didSelectData(_ selectedData: MyTuple<T>) { _didSelectData(selectedData)} init<Delegate: VCADelegate>(delegate: Delegate) where Delegate.T == T { _didSelectData = delegate.didSelectData }}Use that instead of a delegate:class VCA<T>: UIViewController, UITableViewDataSource UITableViewDelegate { var dataList = [MyTuple<T>]() var delegate: AnyVCADelegate<T>? // ... public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { delegate?.didSelectData(dataList[indexPath.row]) }}Your underlying problem is that protocols with associated types are not proper types themselves. They're only type constraints. If you want to keep it a PAT, that's fine, but then you have to make VCA generic over the Delegate:class VCA<Delegate: VCADelegate>: UIViewController, UITableViewDelegate { var dataList = [MyTuple<Delegate.T>]() weak var delegate: Delegate? init(delegate: Delegate?) { self.delegate = delegate super.init(nibName: nil, bundle: nil) } required init(coder: NSCoder) { super.init(nibName: nil, bundle: nil) } public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { delegate?.didSelectData(dataList[indexPath.row]) }}class VCB: UIViewController, VCADelegate { func didSelectData(_ selectedData: MyTuple<String>) {} func callVCA() { let vcA = VCA(delegate: self) vcA.dataList = [(key: "1", value:"Cinnamon"), (key: "2", value:"Cloves")] }}As a rule, protocols with associated types (PATs) are a very powerful, but special-purpose tool. They aren't a replacement for generics (which are a general purpose tool).For this particular problem, though, I'd probably just pass a closure. All a type eraser is (usually) is a struct filled with closures. (Some day the compiler will probably just write them for us, and much of this issue will go away and PATs will be useful in day-to-day code, but for now it doesn't.) 这篇关于通用视图控制器不适用于委托和扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 1403页,肝出来的..
09-06 09:38