Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/99.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift协议、关联类型、自身和默认实现存在问题_Ios_Swift_Swift Protocols_Associated Types_Default Implementation - Fatal编程技术网

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
添加一致性时,我们将
数据
类型别名
a
UICollectionView布局

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
添加一致性时,我们将
数据
类型别名
a
UICollectionView布局

extension UICollectionView: Configurable {
    typealias Data = UICollectionViewLayout
    func configure(data: Data) {
        collectionViewLayout = data
    }
}

就个人而言,我认为这是一种合理的方法,适用于
init(frame:)
初始值设定项不合适的类。

请注意,对于某些类,默认实现将崩溃,例如
UICollectionView
。同时使用
Self()
有点滥用了无参数初始值设定项仍然可用的事实
UIView
,即使对许多子类来说调用它没有意义。最好将这两者分开:实例化和配置。请注意,某些类的默认实现将崩溃,例如
UICollectionView
。同时使用
Self()
有点滥用了无参数初始值设定项仍然可用的事实
UIView
,即使对许多子类来说调用它没有意义。最好将这两个部分分开:实例化和配置。。。天哪,是的!您的init()方法非常有效!非常感谢。“你有点太复杂了”。。。天哪,是的!您的init()方法非常有效!非常感谢。