Ios Swift协议、关联类型、自身和默认实现存在问题
我试图通过默认实现获得一些我无法确定的功能。考虑下面的代码,这是我试图做的一个简化,但是尽可能简单地捕获问题。Ios Swift协议、关联类型、自身和默认实现存在问题,ios,swift,swift-protocols,associated-types,default-implementation,Ios,Swift,Swift Protocols,Associated Types,Default Implementation,我试图通过默认实现获得一些我无法确定的功能。考虑下面的代码,这是我试图做的一个简化,但是尽可能简单地捕获问题。 //protocol definition protocol Configurable { associatedtype Data func configure(data: Data) static func generateObject() -> Self } //default implementation for any UIView exten
//protocol definition
protocol Configurable {
associatedtype Data
func configure(data: Data)
static func generateObject() -> Self
}
//default implementation for any UIView
extension Configurable where Self: UIView {
static func generateObject() -> Self {
return Self()
}
}
//implement protocol for UILabels
extension UILabel: Configurable {
typealias Data = Int
func configure(data: Int) {
label.text = "\(data)"
}
}
//use the protocol
let label = UILabel.generateObject()
label.configure(data: 5)
print(label.text!) //5
我有一个协议,一些UIView方法的默认实现,以及UILabel的特定实现
我的问题是最后一部分。。。所有这些功能的实际使用情况
let label = UILabel.generateObject()
label.configure(data: 5)
print(label.text!) //5
我发现自己一直在做generateObject()
,然后是configure(数据:)
。所以我试着做了以下几点:
向协议中添加静态函数generateObject和configure(数据:data)->Self
。当我尝试为此方法为UIView创建默认实现时,问题就出现了。我得到以下错误
非最终类“UILabel”中的方法“generateObjectAndConfigure(data:)”无法在协议扩展中实现,因为它返回Self,并且具有相关的类型要求
基本上,我不能有一个返回Self
并使用关联类型的方法。我总是连续调用这两种方法,这感觉真的很糟糕。我只想为每个类声明configure(Data)
,并免费获取generateObject和configure(Data)
有什么建议吗?通过使用
Self
,您的操作有点过于复杂了
您只需在可配置
协议中声明一个初始化器,该初始化器接受数据
关联类型
作为参数,并具有非静态配置功能:
protocol Configurable {
associatedtype Data
init(data: Data)
func configure(data: Data)
}
在Configurable
协议的扩展中提供该初始值设定项的默认实现(对于UIView
及其子类):
最后,通过对您感兴趣的任何UIView
子类的扩展,为协议添加一致性。在这里,您只需实现typealias
和configure
方法:
extension UILabel: Configurable {
typealias Data = Int
func configure(data: Data) {
text = "\(data)"
}
}
此实现还有一个额外的好处,即您使用初始值设定项来创建视图(用于实例化对象的标准Swift模式),而不是静态方法:
let label = UILabel(data: 10)
let imageView = UIImageView(data: "screenshot")
我不太清楚为什么编译器不喜欢你的版本。我本以为UILabel
的子类会继承typealias
,这意味着编译器在推断Self
和Data
时不会有问题,但显然这还不受支持
编辑:@Cristik在评论中对UICollectionView
提出了很好的观点
此问题可以通过为可配置
添加协议扩展来解决,其中自身
为UICollectionView
,使用适当的初始值设定项:
extension Configurable where Self: UICollectionView {
init(data: Data) {
self.init(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout())
self.configure(data: data)
}
}
然后,当为UICollectionView
向Configurable
添加一致性时,我们将数据
类型别名
aUICollectionView布局
:
extension UICollectionView: Configurable {
typealias Data = UICollectionViewLayout
func configure(data: Data) {
collectionViewLayout = data
}
}
就个人而言,我认为这是一种合理的方法,适用于
init(frame:)
初始值设定项不合适的类。通过使用Self
,这有点过于复杂了
您只需在可配置
协议中声明一个初始化器,该初始化器接受数据
关联类型
作为参数,并具有非静态配置功能:
protocol Configurable {
associatedtype Data
init(data: Data)
func configure(data: Data)
}
在Configurable
协议的扩展中提供该初始值设定项的默认实现(对于UIView
及其子类):
最后,通过对您感兴趣的任何UIView
子类的扩展,为协议添加一致性。在这里,您只需实现typealias
和configure
方法:
extension UILabel: Configurable {
typealias Data = Int
func configure(data: Data) {
text = "\(data)"
}
}
此实现还有一个额外的好处,即您使用初始值设定项来创建视图(用于实例化对象的标准Swift模式),而不是静态方法:
let label = UILabel(data: 10)
let imageView = UIImageView(data: "screenshot")
我不太清楚为什么编译器不喜欢你的版本。我本以为UILabel
的子类会继承typealias
,这意味着编译器在推断Self
和Data
时不会有问题,但显然这还不受支持
编辑:@Cristik在评论中对UICollectionView
提出了很好的观点
此问题可以通过为可配置
添加协议扩展来解决,其中自身
为UICollectionView
,使用适当的初始值设定项:
extension Configurable where Self: UICollectionView {
init(data: Data) {
self.init(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout())
self.configure(data: data)
}
}
然后,当为UICollectionView
向Configurable
添加一致性时,我们将数据
类型别名
aUICollectionView布局
:
extension UICollectionView: Configurable {
typealias Data = UICollectionViewLayout
func configure(data: Data) {
collectionViewLayout = data
}
}
就个人而言,我认为这是一种合理的方法,适用于
init(frame:)
初始值设定项不合适的类。请注意,对于某些类,默认实现将崩溃,例如UICollectionView
。同时使用Self()
有点滥用了无参数初始值设定项仍然可用的事实UIView
,即使对许多子类来说调用它没有意义。最好将这两者分开:实例化和配置。请注意,某些类的默认实现将崩溃,例如UICollectionView
。同时使用Self()
有点滥用了无参数初始值设定项仍然可用的事实UIView
,即使对许多子类来说调用它没有意义。最好将这两个部分分开:实例化和配置。。。天哪,是的!您的init()方法非常有效!非常感谢。“你有点太复杂了”。。。天哪,是的!您的init()方法非常有效!非常感谢。