Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conform to a protocol's variables' set & get?

Tags:

I'm playing around with protocols and how to conform to them.

protocol Human {         var height: Int { get set }     }  struct Boy: Human {      var height: Int  { return 5 } // error! } 

I'm trying to learn different ways that I can implement set and get. However the code above throws the following error:

type 'Boy' does not conform to protocol 'Human'

However writing as below won't have any errors:

struct Boy: Human {      var height = 5 // no error } 

I don't understand the difference nor what exactly needs to be implemented when you can also set a variable. I looked into different questions and tutorials but they all just write and go without any deeper explanation.

EDIT: make sure you see Imanou's answer here. It greatly explains the different scenarios.

like image 874
mfaani Avatar asked Nov 26 '16 17:11

mfaani


People also ask

Can we declare variables in protocol?

The protocol doesn't specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. Property requirements are always declared as variable properties, prefixed with the var keyword.

Is it possible to prevent the adoption of a protocol by a struct?

A protocol defines a blueprint of methods, properties, and other requirements. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. But there would be a time when you want to restrict protocols to be adopted by a specific class.

How many protocols can a Swift class adopt?

Swift 4 allows multiple protocols to be called at once with the help of protocol composition.

Can Swift protocols have properties?

A protocol can have properties as well as methods that a class, enum or struct conforming to this protocol can implement. A protocol declaration only specifies the required property name and type.


2 Answers

From the Swift Reference:

Property Requirements

...
The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type.
...
Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }.

In your case

var height: Int  {return 5} // error! 

is a computed property which can only be get, it is a shortcut for

var height: Int {     get {         return 5     } } 

But the Human protocol requires a property which is gettable and settable. You can either conform with a stored variable property (as you noticed):

struct Boy: Human {      var height = 5 } 

or with a computed property which has both getter and setter:

struct Boy: Human {      var height: Int {         get {             return 5         }         set(newValue) {             // ... do whatever is appropriate ...         }     } } 
like image 109
Martin R Avatar answered Oct 05 '22 18:10

Martin R


Prerequisite:

Go into your playground and just write the snippet below:

var height: Int {     get {         return 5     } }     

or similarly:

var height: Int {     return 5 }     

Try to print height's value, obviously works. So far so good

print(height) // prints 5 

However if you try to set it to a new value then you'll get an error:

height = 8 // ERROR   

error: cannot assign to value: 'height' is a get-only property


Answer:

Based on Martin's answer, I first wrote:

set(newValue) {     height = newValue  } 

Which put a ton of load on my memory and led me to this question. Please take a look. So then I was figuring out what to write, and I kind of understood that if you don't want to do anything special you shouldn't be using computed properties and instead you should just use normal stored properties.

So I wrote a similar code

protocol Human {      var height: Float {get set}  }  struct Boy: Human {      // inch     var USheight : Float      // cm     var height: Float {         get {             return 2.54 * USheight         }         set(newValue) {          USheight = newValue/2.54          }     } }  // 5 ft person var person = Boy(USheight: 60)  // interestingly the initializer is 'only' based on stored properties because they  // initialize computed properties.    // equals to 152cm person print(person.height) // 152.4 

Pro tip: When should you should make your properties read-only?

Normally if you make a property to be read-only ie { get } it's because those properties are computed and you don't want the object to have control over it.

Example you have a JSON object. It has multiple big objects like:

JSONData  - userInfo (name, address, age)  - devices (iPads, iPhones, Mac books)  - credentials (basic iCloud, pro iCloud, celebrity) 

by making the role a read-only you're only allowing the server to tell the code base the role of the user.

protocol Credentials {     var role: String { get }      init(person: Person) }  class Person {     var userInfo: String     var devices: [String]     var creds: Credentials {         Credentials(person: self)     }      init(userInfo: userInfo, devices: [String]) {         self.userInfo = userInfo         self.devices = devices     } } 
like image 40
mfaani Avatar answered Oct 05 '22 18:10

mfaani