如何在协议扩展中定义初始值设定项?
How to define initializers in a protocol extension?
protocol Car {
var wheels : Int { get set}
init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.wheels = wheels
}
}
on self.wheels = wheels 我得到错误
Error: variable 'self' passed by reference before being initialized
如何在协议扩展中定义初始化程序?
我的理解是这是不可能的,因为协议扩展不知道符合要求的 class 或结构有哪些属性 - 因此不能保证它们被正确初始化。
如果有办法解决这个问题,我很想知道! :)
如您所见,这在这些情况下不起作用,因为在编译时,必须确保在使用 struct/enum/class.
之前初始化所有属性
您可以要求另一个初始化程序,以便编译器知道所有属性都已初始化:
protocol Car {
var wheels : Int { get set }
// make another initializer
// (which you probably don't want to provide a default implementation)
// a protocol requirement. Care about recursive initializer calls :)
init()
init(wheels: Int)
}
extension Car {
// now you can provide a default implementation
init(wheels: Int) {
self.init()
self.wheels = wheels
}
}
// example usage
// mark as final
final class HoverCar: Car {
var wheels = 0
init() {}
}
let drivableHoverCar = HoverCar(wheels: 4)
drivableHoverCar.wheels // 4
从 Xcode 7.3 beta 1 开始,它可以按预期与 structs
一起使用,但不能与 类 一起使用,因为如果它们不是 final
中的 init(wheels: Int)
该协议是一个 required init
,它可以被覆盖,因此不能通过扩展添加。解决方法(如编译器建议的那样):使 class
final
.
另一种解决方法(深入;没有 final class
)
要使用 类 而不是将它们定为最终版本,您还可以删除协议中的 init(wheels: Int)
要求。它的行为似乎与以前没有什么不同,但请考虑以下代码:
protocol Car {
var wheels : Int { get set }
init()
// there is no init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.init()
print("Extension")
self.wheels = wheels
}
}
class HoverCar: Car {
var wheels = 0
required init() {}
init(wheels: Int) {
print("HoverCar")
self.wheels = wheels
}
}
// prints "HoverCar"
let drivableHoverCar = HoverCar(wheels: 4)
func makeNewCarFromCar<T: Car>(car: T) -> T {
return T(wheels: car.wheels)
}
// prints "Extension"
makeNewCarFromCar(drivableHoverCar)
因此,如果您从通用上下文创建一个 Car
,其中您调用 init
的类型仅被称为 Car
,即使初始值设定项在 HoverCar
中定义。这只是因为协议中没有 init(wheels: Int)
要求。
如果添加它,您会遇到之前将 class
声明为 final
的问题,但现在它会打印两次 "HoverCar"。无论哪种方式,第二个问题可能永远不会发生,所以它可能是一个更好的解决方案。
旁注:如果我犯了一些错误(代码、语言、语法等),欢迎您纠正我:)
@Qbyte 正确
另外,你可以看看我的Configurable
因为我有 Initable
协议
public protocol Initable {
// To make init in protocol extension work
init()
}
public extension Initable {
public init(@noescape block: Self -> Void) {
self.init()
block(self)
}
}
那么为了符合它
extension Robot: Initable { }
我有两种方法,使用 final
或实现 init
final class Robot {
var name: String?
var cute = false
}
class Robot {
var name: String?
var cute = false
required init() {
}
}
可能不一样,但在我的例子中,我没有使用 init,而是使用静态函数 return class 的对象。
protocol Serializable {
static func object(fromJSON json:JSON) -> AnyObject?
}
class User {
let name:String
init(name:String) {
self.name = name
}
}
extension User:Serializable {
static func object(fromJSON json:JSON) -> AnyObject? {
guard let name = json["name"] else {
return nil
}
return User(name:name)
}
}
然后为了创建对象,我做了类似的事情:
let user = User.object(fromJSON:json) as? User
我知道这不是有史以来最好的事情,但它是我能找到的最好的解决方案,不会将业务模型与数据层耦合。
注意:我很懒惰,我直接在评论中编写所有代码,所以如果有什么不对请告诉我。
protocol Car {
var wheels : Int { get set}
init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.wheels = wheels
}
}
on self.wheels = wheels 我得到错误
Error: variable 'self' passed by reference before being initialized
如何在协议扩展中定义初始化程序?
我的理解是这是不可能的,因为协议扩展不知道符合要求的 class 或结构有哪些属性 - 因此不能保证它们被正确初始化。
如果有办法解决这个问题,我很想知道! :)
如您所见,这在这些情况下不起作用,因为在编译时,必须确保在使用 struct/enum/class.
之前初始化所有属性您可以要求另一个初始化程序,以便编译器知道所有属性都已初始化:
protocol Car {
var wheels : Int { get set }
// make another initializer
// (which you probably don't want to provide a default implementation)
// a protocol requirement. Care about recursive initializer calls :)
init()
init(wheels: Int)
}
extension Car {
// now you can provide a default implementation
init(wheels: Int) {
self.init()
self.wheels = wheels
}
}
// example usage
// mark as final
final class HoverCar: Car {
var wheels = 0
init() {}
}
let drivableHoverCar = HoverCar(wheels: 4)
drivableHoverCar.wheels // 4
从 Xcode 7.3 beta 1 开始,它可以按预期与 structs
一起使用,但不能与 类 一起使用,因为如果它们不是 final
中的 init(wheels: Int)
该协议是一个 required init
,它可以被覆盖,因此不能通过扩展添加。解决方法(如编译器建议的那样):使 class
final
.
另一种解决方法(深入;没有 final class
)
要使用 类 而不是将它们定为最终版本,您还可以删除协议中的 init(wheels: Int)
要求。它的行为似乎与以前没有什么不同,但请考虑以下代码:
protocol Car {
var wheels : Int { get set }
init()
// there is no init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.init()
print("Extension")
self.wheels = wheels
}
}
class HoverCar: Car {
var wheels = 0
required init() {}
init(wheels: Int) {
print("HoverCar")
self.wheels = wheels
}
}
// prints "HoverCar"
let drivableHoverCar = HoverCar(wheels: 4)
func makeNewCarFromCar<T: Car>(car: T) -> T {
return T(wheels: car.wheels)
}
// prints "Extension"
makeNewCarFromCar(drivableHoverCar)
因此,如果您从通用上下文创建一个 Car
,其中您调用 init
的类型仅被称为 Car
,即使初始值设定项在 HoverCar
中定义。这只是因为协议中没有 init(wheels: Int)
要求。
如果添加它,您会遇到之前将 class
声明为 final
的问题,但现在它会打印两次 "HoverCar"。无论哪种方式,第二个问题可能永远不会发生,所以它可能是一个更好的解决方案。
旁注:如果我犯了一些错误(代码、语言、语法等),欢迎您纠正我:)
@Qbyte 正确
另外,你可以看看我的Configurable
因为我有 Initable
协议
public protocol Initable {
// To make init in protocol extension work
init()
}
public extension Initable {
public init(@noescape block: Self -> Void) {
self.init()
block(self)
}
}
那么为了符合它
extension Robot: Initable { }
我有两种方法,使用 final
或实现 init
final class Robot {
var name: String?
var cute = false
}
class Robot {
var name: String?
var cute = false
required init() {
}
}
可能不一样,但在我的例子中,我没有使用 init,而是使用静态函数 return class 的对象。
protocol Serializable {
static func object(fromJSON json:JSON) -> AnyObject?
}
class User {
let name:String
init(name:String) {
self.name = name
}
}
extension User:Serializable {
static func object(fromJSON json:JSON) -> AnyObject? {
guard let name = json["name"] else {
return nil
}
return User(name:name)
}
}
然后为了创建对象,我做了类似的事情:
let user = User.object(fromJSON:json) as? User
我知道这不是有史以来最好的事情,但它是我能找到的最好的解决方案,不会将业务模型与数据层耦合。
注意:我很懒惰,我直接在评论中编写所有代码,所以如果有什么不对请告诉我。