Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 452
Axort Avatar asked Aug 11 '16 00:08

Axort


People also ask

Can Swift extensions add properties?

Extensions in Swift can: Add computed instance properties and computed type properties. Define instance methods and type methods. Provide new initializers.

Can Swift protocols have properties?

Protocols provide a blueprint for Methods, properties and other requirements functionality. It is just described as a methods or properties skeleton instead of implementation. Methods and properties implementation can further be done by defining classes, functions and enumerations.

Why extensions Cannot have stored properties?

error: extensions may not contain stored properties . It means that Swift doesn't support stored properties inside the extension. Therefore, we cannot use the toggleState property to keep the internal state of our toggle button. For this reason, we need a workaround.

What is default protocol in Swift?

Protocol Default Implementation “You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol.” In fact, not only can you provide a default implementation to methods or computed properties defined in the protocol, you can also add new ones.

What are extensions in Swift?

Extensions in Swift can: Add computed instance properties and computed type properties In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of. For more details, see Protocol Extensions.

Can you extend a protocol in Swift?

In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of. For more details, see Protocol Extensions. Extensions can add new functionality to a type, but they cannot override existing functionality.

What are computed instance properties in Swift’s double?

This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: These computed properties express that a Double value should be considered as a certain unit of length.

Why do Swift protocols have capital letters?

Because protocols are types, begin their names with a capital letter (such as FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double ). Here’s an example of a protocol used as a type: This example defines a new class called Dice, which represents an n -sided dice for use in a board game.


1 Answers

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 
like image 108
Luca Angeletti Avatar answered Sep 28 '22 16:09

Luca Angeletti