Swift 协议扩展初始值设定项
我想知道一个简单类中的初始值设定项的协议等价物是什么,该类只包含初始化功能,并且只打算在具体类中进行扩展 因此,最简单的方法可能是显示代码-我正在寻找与以下内容等效的协议扩展:Swift 协议扩展初始值设定项,swift,initialization,swift2,protocols,Swift,Initialization,Swift2,Protocols,我想知道一个简单类中的初始值设定项的协议等价物是什么,该类只包含初始化功能,并且只打算在具体类中进行扩展 因此,最简单的方法可能是显示代码-我正在寻找与以下内容等效的协议扩展: import UIKit class Thing { var color:UIColor init(color:UIColor) { self.color = color } } class NamedThing:Thing { var name:String i
import UIKit
class Thing {
var color:UIColor
init(color:UIColor) {
self.color = color
}
}
class NamedThing:Thing {
var name:String
init(name:String,color:UIColor) {
self.name = name
super.init(color:color)
}
}
var namedThing = NamedThing(name: "thing", color: UIColor.blueColor())
我希望代码看起来像:
protocol Thing {
var color:UIColor {get set}
}
extension Thing {
init(color:UIColor) {
self.color = color
}
}
class NamedThing:Thing {
var name:String
var color:UIColor
init(name:String,color:UIColor) {
self.name = name
self.init(color:color)
}
}
import UIKit
protocol Colorable {
var color: UIColor {get set}
}
protocol Nameable {
var name: String {get set}
}
class ColoredNamedThing: Colorable, Nameable {
var name: String
var color: UIColor
init(name: String, color: UIColor) {
self.name = name
self.color = color
}
}
var coloredNamedThing = ColoredNamedThing(name: "Name", color: UIColor.redColor())
我在其他StackOverflow问题(例如)中看到过建议的解决方案,但我不确定它们是否有效,也不确定它们是否具体解决了类初始值设定项中附加参数的问题 您必须提供一个有效的init链来创建类的实例,这限制了您在协议中对初始值设定项的选择
class ManagedColors
{
var color:UIColor
// other related variables that need a common initialisation
// ...
init(color:UIColor)
{
self.color = color
// common initialisations for the other variables
}
}
protocol ManagedColorClass
{
var managedColors:ManagedColors { get }
}
extension ManagedColorClass
{
// makes properties of the delegate class accessible as if they belonged to the
// class that uses the protocol
var color:UIColor {
get { return managedColors.color }
set { managedColors.color = newValue }
}
}
// NamedThing objects will be able to use .color as if it had been
// declared as a variable of the class
//
// if you add more properties to ManagedColors (and the ManagedColorHost protocol)
// all your classes will inherit the properties as if you had inherited from them through a superclass
//
// This is an indirect way to achive multiple inheritance, or add additional STORED variables with
// a protocol
//
class NamedThing:ManagedColorClass
{
var name:String
var managedColors:ManagedColors
init(name:String,color:UIColor)
{
managedColors = ManagedColors(color:color)
self.name = name
}
}
let red = NamedThing(name:"red", color:UIColor.redColor())
print(" \(red.name) \(red.color)")
由于您的协议不能确定覆盖使用它的类的所有成员,因此您在协议中声明的任何初始值设定项都需要将该类的“未知”成员的初始化委托给该类本身提供的另一个初始值设定项
我调整了您的示例,以使用basic init()作为协议的委托初始值设定项来说明这一点
如您所见,这需要在调用init()时为所有成员实现初始值。在本例中,我通过在每个成员的声明中提供默认值来实现这一点。而且,由于某些成员并不总是有实际的初始值,所以我将其更改为“自动展开”选项
为了使thinks更有趣,您的类不能将初始化委托给协议提供的初始值设定项,除非它通过方便的初始值设定项这样做
我不知道这些限制是否值得费心。我怀疑您正在尝试使用协议,因为您需要在实现协议的类之间一致地初始化一组公共变量。也许使用委托类可以提供比协议更简单的解决方案(只是一个想法)
以下是我对“委派类”的想法 这是一种使用协议将存储变量添加到类中的技术
class ManagedColors
{
var color:UIColor
// other related variables that need a common initialisation
// ...
init(color:UIColor)
{
self.color = color
// common initialisations for the other variables
}
}
protocol ManagedColorClass
{
var managedColors:ManagedColors { get }
}
extension ManagedColorClass
{
// makes properties of the delegate class accessible as if they belonged to the
// class that uses the protocol
var color:UIColor {
get { return managedColors.color }
set { managedColors.color = newValue }
}
}
// NamedThing objects will be able to use .color as if it had been
// declared as a variable of the class
//
// if you add more properties to ManagedColors (and the ManagedColorHost protocol)
// all your classes will inherit the properties as if you had inherited from them through a superclass
//
// This is an indirect way to achive multiple inheritance, or add additional STORED variables with
// a protocol
//
class NamedThing:ManagedColorClass
{
var name:String
var managedColors:ManagedColors
init(name:String,color:UIColor)
{
managedColors = ManagedColors(color:color)
self.name = name
}
}
let red = NamedThing(name:"red", color:UIColor.redColor())
print(" \(red.name) \(red.color)")
太棒了,没问题
extension Thing {
init(color: UIColor) {
self.color = color
}
}
不,那是行不通的。这违反了太多的规则。首先也是最重要的一点是,这并不一定设置所有属性。考虑你的代码> NamedThing < /代码>。在这种情况下,name
是什么?如果color
setter获取其他尚未设置的属性,会发生什么情况?编译器还不能看到所有可能的实现,所以它不知道color
是否只是一个ivar或者更复杂的东西。不,这行不通
真正的问题是“一个可以在具体类中扩展的抽象类。”忘记类吧。忘记继承吧。Swift是关于组合和协议的,而不是继承
因此,让我们考虑一下您在注释中描述的示例(尽管在Cocoa中,也没有“抽象类”)。让我们假设设置颜色实际上是许多您不想复制的代码。没问题。你只需要一个函数
import UIKit
protocol Thing {
var color: UIColor {get set}
}
private extension Thing {
static func colorForColor(color: UIColor) -> UIColor {
// We don't really use the color directly. We have some complicated code that we don't want to repeat
return color
}
}
final class NamedThing: Thing {
var name: String
var color: UIColor
init(name: String, color: UIColor) {
self.name = name
self.color = NamedThing.colorForColor(color)
}
}
由于扩展的目的是处理部分初始化,只需让它计算所需的部分即可。不要试图使它成为扩展中的初始值设定项,因为它必须负责初始化所有内容,而当您将它与继承混合使用时,这是很难正确完成的。我得出的结论是,这个问题有点无法回答,因为协议扩展无法动态定义属性(除非它为属性提供默认值,或将它们声明为隐式展开)。要以更面向协议的方式解决此问题,它需要一种不同的方法,这仍然涉及声明和初始化具体类中的所有变量,例如:
protocol Thing {
var color:UIColor {get set}
}
extension Thing {
init(color:UIColor) {
self.color = color
}
}
class NamedThing:Thing {
var name:String
var color:UIColor
init(name:String,color:UIColor) {
self.name = name
self.init(color:color)
}
}
import UIKit
protocol Colorable {
var color: UIColor {get set}
}
protocol Nameable {
var name: String {get set}
}
class ColoredNamedThing: Colorable, Nameable {
var name: String
var color: UIColor
init(name: String, color: UIColor) {
self.name = name
self.color = color
}
}
var coloredNamedThing = ColoredNamedThing(name: "Name", color: UIColor.redColor())
感谢@alain-t的回答,我将接受这个答案,因为它最接近于找到我问题的解决方案,尽管它包含隐式的未包装属性
感谢@rob napier也为您的贡献。符合AnyObject us冗余、隐式展开的名称和颜色是危险的,不需要(改为设置默认值)感谢您富有洞察力的评论,您似乎遇到了与我类似的障碍。我同意您的评论,即这是否值得麻烦。我想我正在寻找以面向协议的方法实现上述问题的最佳实践。需要为VAR提供默认值或使其隐式解包并不重要“对我来说,这似乎不太方便,也不是最佳做法,这让我怀疑使用协议是否不是解决此问题的正确方法。@alain-t您能用代码示例填写您对“委托类”的评论吗?@CraigGrummitt swift中的所有变量(和/或常量)在使用之前必须具有一定的值(对于引用类型,它在Swift中表示为一个类,值是引用,对于值类型,它是值本身)。不存在null的直接等价物是Swift。var i=Optional()的默认值为nil。var j=ImplicitlyUnwrappedOptional()给出相同的结果(两者都是enum‘type’)…(下面继续)@CraigGrummitt(继续)…但如果您在某个地方使用它,编译器将不会抱怨,并且您的代码很可能会崩溃。这就是为什么var name:String!=nil不是最佳解决方案。在您的示例中,最好是使用非可选值。var name:String=”“应该可以工作,对我来说似乎非常方便:-)以及最佳实践。感谢你的anwer Rob。为了简单起见,我已经将代码简化为一个简单的示例,没有讨论为什么它需要成为一个类,但在现实生活中的示例中,它是一个需要实现协议的类,因为它将成为UIKit类的子类。样板代码旨在通过处理颜色设置的e协议扩展。顺便说一句,我刚刚通过你的评论“There ar