协议扩展初始化程序

Cra*_*itt 11 protocols initialization swift swift2

我想知道在一个只包含初始化功能的简单类中初始化器的协议等价物是什么,并且仅用于在具体类中扩展.

所以最简单的方法就是显示代码 - 我正在寻找相当于以下内容的协议扩展:

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())
Run Code Online (Sandbox Code Playgroud)

我期待代码看起来像:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经看到其他StackOverflow问题中建议的解决方案(例如,如何在协议扩展中定义初始化器?)但我不确定它们是否有效,也没有专门解决类初始化程序中的其他参数问题.

Ala*_* T. 15

您必须提供一个有效的init链来创建类的实例,并限制协议中初始化程序的选项.

由于您的协议无法确定涵盖使用它的类的所有成员,因此您在协议中声明的任何初始化程序都需要将类的"未知"成员的初始化委托给类本身提供的另一个初始化程序.

我调整了您的示例以使用基本的init()作为协议的委托初始化程序来说明这一点.

如您所见,这要求您的类在调用init()时为所有成员实现初始值.在这种情况下,我通过在每个成员的声明中提供默认值来做到这一点.而且,由于某些成员并不总是有实际的初始值,我将其更改为自动解包选项.

并且为了使思考更有趣,您的类不能将初始化委托给协议提供的初始化程序,除非它通过便利初始化程序这样做.

我想知道所有这些限制是否值得麻烦.我怀疑你正在尝试使用协议,因为你需要在实现协议的类之间一致地初始化一堆公共变量.也许使用委托类会提供比协议更简单的解决方案(只是一个想法).

protocol Thing:AnyObject
{
    var color:UIColor! { get set }
    init()
}

extension Thing 
{    
    init(color:UIColor)
    {  
       self.init()
       self.color = color
    }
}

class NamedThing:Thing 
{
    var name:String!   = nil
    var color:UIColor! = nil

    required init() {}

    convenience init(name:String,color:UIColor) 
    {
        self.init(color:color)
        self.name = name
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 符合AnyObject我们多余的,隐式展开的名称和颜色是危险的而不是必需的(改为设置默认值) (2认同)

Rob*_*ier 13

protocol Thing {
    var color: UIColor {get set}
}
Run Code Online (Sandbox Code Playgroud)

太棒了,没问题.

extension Thing {
    init(color: UIColor) {
        self.color = color
    }
}
Run Code Online (Sandbox Code Playgroud)

不,那永远不会奏效.这打破了太多规则.第一个也是最重要的是,这并不一定会设置所有属性.考虑你的NamedThing.什么是name在这种情况下?如果colorsetter获取尚未设置的其他属性会发生什么?编译器还看不到每个可能的实现,所以它不知道是否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)
    }
}
Run Code Online (Sandbox Code Playgroud)

由于您的扩展点是处理部分初始化,只需让它计算您需要的部分.不要试图使它成为扩展中的初始化器,因为它必须负责初始化所有内容,当你将它与继承混合时很难正确完成.