Swift Protocol get only settable?
As per the official documentation:
The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property.
Swift Protocols: Difference between { get } and { get set } with concrete examples?
protocol
— is a requirement of some minimal interface of the type implementing it.
var name: Type { get }
requires type to have property with at least agetter
(accessible from outside of the type, notprivate
), i.e. outside code should be able to read value of the property. In the implementing type it could belet name: Type
,var name: Type
,private(set) var name: Type
,fileprivate(set) var name: Type
, etc.var name: Type { get set }
requires type to have property with both accessiblegetter
andsetter
, i.e. outside code should be able to read and write to the property. Here onlyvar name: Type
would be allowed.
If protocol
requires for getter
but you also provide a setter
— it's not against protocol
requirements.
But if protocol
requires for both getter
and setter
— you must provide both, and not having any of them won't be valid implementation.
Your Person
class defined both properties as var
(with accessible getter
and setter
) therefore you can change them both. But PersonProtocol
haven't required ability to set firstName
.
And as @JoakimDanielson shows, if you will use just interface required by protocol
you won't be to change the firstName
value.
Swift protocol settable property through a read-only property
Change your protocol declaration to this:
protocol AProtocol:class {
var name: String { get set }
}
Otherwise, it is taken by default as a value type. Changing a value type's property replaces the value type instance (as shown by the setter observer). And you can't do that if the reference is a let
reference.
Why am I allowed to set a read only property of a protocol using a struct that inherits said protocol?
What am I doing wrong to make it a true read only property to where I can't set it?
There is a difference between a protocol (a set of rules) and the type (i.e. your struct) that adopts the protocol.
Your protocol rule says that
readOnlyProperty
should be readable.Your struct obeys by making it readable, and also makes it writable. That is not illegal, so all is well — and
readOnlyProperty
in your struct is read-write.
What would have been illegal would be the inverse, i.e. for the protocol to declare a property read-write but the adopter to declare it read-only. That situation didn't arise in your example, but if it had, the compiler would have stopped you.
Specify a settable property/variable in a protocol
The protocol might be implemented by either classes and structs - that prevents you from changing the internal status of an instance of a class or struct implementing that protocol using an immutable variable.
To fix the problem you have to either declare the food
variable as mutable:
func eat() {
var food = nextItem
food.eaten = true // (!) ERROR: Cannot assign to result of this expression
}
or declare the EdibleThing
protocol to be implementable by classes only:
protocol EdibleThing : class {
var eaten: Bool { get set }
}
Note that this happens because food
is a variable of EdibleThing
type - the compiler doesn't know if the actual instance is a value or reference type, so it raises an error. If you make it a variable of a class type, like this:
let food: Pickle = nextItem as! Pickle
the compiler knows without any ambiguity that it's a reference type, and in that case it allows the assignment. But I guess that breaks your app logic... so consider it just as an example
How to conform to a protocol's variables' set & get?
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 thevar
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 ...
}
}
}
Swift protocol property of type Set Self
The way to put constraints in protocols is similar to how you specify protocol conformance (they're the same thing after all)
protocol Groupable: Hashable
{
var parent: Self? { get }
var children: Set<Self> { get }
}
Swift protocols mutability
The protocol requirement is
a variable
name
which can be read
which doesn't mean that the variable in a struct adopting this protocol is necessarily read-only.
In the code you are changing the variable directly in the Driver
type, the protocol is not involved.
On the other hand if you annotate the protocol type you get the expected error
var driver : Person = Driver(name: "Ryan")
driver.name = "Changed!" // Cannot assign to property: 'name' is a get-only property
Related Topics
Uitableview Reloaddata Automatically Calls Resignfirstresponder
Pushing a Navigation Controller Is Not Supported
How to Get the iOS Device CPU Architecture in Runtime
Deploying an iOS Application Using Apple Enterprise Developer Program
How to Know Users Click Fast Forward and Fast Rewind Buttons on the Playback Controls in Iphone
iOS 8 Keyboard Hides My Textview
Converting Nsdictionary Object to Nsdata Object and Vice-Versa
iOS 14 How to Trigger Local Network Dialog and Check User Answer
How to Properly Order Data from Firebase Chronologically
Using Mdm to Configure an Enterprise App via Nsuserdefaults
Cordova Run with iOS Error .. Error Code 65 for Command: Xcodebuild with Args:
"Could Not Find Developer Disk Image"
Swift: Long Press Gesture Recognizer - Detect Taps and Long Press
App Transport Security Has Blocked a Cleartext Http Resource
Dynamically Increase Height of Uilabel & Tableview Cell
Code Signing Is Required for Product Type Unit Test Bundle in Sdk iOS 8.0