Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.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
Swift 协议扩展初始值设定项_Swift_Initialization_Swift2_Protocols - Fatal编程技术网

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