protocol Car {
var wheels : Int { get set}
init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.wheels = wheels
}
}
self.wheels =ホイールでエラーが発生します
Error: variable 'self' passed by reference before being initialized
プロトコル拡張で初期化子を定義するにはどうすればよいですか?
ご覧のとおり、これらの状況ではこれは機能しません。コンパイル時に、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
として宣言するという前の問題がありますが、今では2回「HoverCar」と表示されます。いずれにしても、2番目の問題はおそらく発生しないので、より良い解決策になる可能性があります。
サイドノート:間違い(コード、言語、文法など)を犯した場合は、私を修正してください:)
@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
を実装する2つの方法があります
final class Robot {
var name: String?
var cute = false
}
class Robot {
var name: String?
var cute = false
required init() {
}
}
プロトコル拡張は適合クラスまたは構造体がどのプロパティを持っているかを知ることができないため、これらが正しく初期化されることを保証できないため、私の理解ではこれは不可能です。
これを回避する方法がある場合、私は知ることに非常に興味があります! :)
同じではないかもしれませんが、私の場合は、initを使用する代わりに、静的funcを使用してクラスのオブジェクトを返します。
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
私はそれが今までで最高のものではないことを知っていますが、ビジネスモデルをデータレイヤーと結び付けないために見つけることができる最高のソリューションです。
注:私は怠け者であり、コメント内のすべてを直接コーディングしたので、うまくいかない場合はお知らせください。