Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
385 views
in Technique[技术] by (71.8m points)

ios - Swift - Protocol extensions - Property default values

Let's say that I have the following protocol:

protocol Identifiable {
    var id: Int {get}
    var name: String {get}
}

And that I have the following structs:

struct A: Identifiable {
    var id: Int
    var name: String
}

struct B: Identifiable {
    var id: Int
    var name: String
}

As you can see, I had to 'conform' to the Identifiable protocol in struct A and struct B. But imagine if I had N more structs that needs to conform to this protocol... I don't want to 'copy/paste' the conformance (var id: Int, var name: String)

So I create a protocol extension:

extension Identifiable {
    var id: Int {
        return 0
    }

    var name: String {
        return "default"
    }
}

With this extension now I can create a struct that conforms to the Identifiable protocol without having to implement both properties:

struct C: Identifiable {

}

Now the problem is that I can't set a value to the id property or the name property:

var c: C = C()
c.id = 12 // Cannot assign to property: 'id' is a get-only property

This happens because in the Identifiable protocol, id and name are only gettable. Now if I change the id and name properties to {get set} I get the following error:

Type 'C' does not conform to protocol 'Identifiable'

This error happens because I haven't implemented a setter in the protocol extension... So I change the protocol extension:

extension Identifiable {
    var id: Int {
        get {
            return 0
        }

        set {

        }
    }

    var name: String {
        get {
            return "default"
        }

        set {

        }
    }
}

Now the error goes away but if I set a new value to id or name, it gets the default value (getter). Of course, the setter is empty.

My question is: What piece of code do I have to put inside the setter? Because if I add self.id = newValue it crashes (recursive).

Thanks in advance.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It seems you want to add a stored property to a type via protocol extension. However this is not possible because with extensions you cannot add a stored property.

I can show you a couple of alternatives.

Subclassing (Object Oriented Programming)

The easiest way (as probably you already imagine) is using classes instead of structs.

class IdentifiableBase {
    var id = 0
    var name = "default"
}

class A: IdentifiableBase { }

let a = A()
a.name  = "test"
print(a.name) // test

Cons: In this case your A class needs to inherit from IdentifiableBase and since in Swift theres is not multiple inheritance this will be the only class A will be able to inherit from.

Components (Protocol Oriented Programming)

This technique is pretty popular in game development

struct IdentifiableComponent {
    var id = 0
    var name = "default"
}

protocol HasIdentifiableComponent {
    var identifiableComponent: IdentifiableComponent { get set }
}

protocol Identifiable: HasIdentifiableComponent { }

extension Identifiable {
    var id: Int {
        get { return identifiableComponent.id }
        set { identifiableComponent.id = newValue }
    }
    var name: String {
        get { return identifiableComponent.name }
        set { identifiableComponent.name = newValue }
    }
}

Now you can make your type conform to Identifiable simply writing

struct A: Identifiable {
    var identifiableComponent = IdentifiableComponent()
}

Test

var a = A()
a.identifiableComponent.name = "test"
print(a.identifiableComponent.name) // test

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...