In Swift do you not have to use a getter and setter when creating an object type, such as class, that conforms to a protocol requiring so? - swift

protocol UserType {
var name: String { get }
var age: Int { get set }
struct Person: UserType {
var name: String //<- why is this okay?
var age: Int //<- why is this okay? dont we need a getter setter
}
let somePerson = Person(name: "Billy", age: 22)
Why in the above examples, we dont use get constructs or set constructs for age and a get construct for name? Is it because in the protocol when the property is said to "{ get set }" that essentially means it has to be able to be read and has to be able to be changed, which can be done through a declaration in the syntax of a stored property?
Thanks!

protocol UserType {
var name: String { get }
var age: Int { get set }
}
The important thing to understand is that { get } and { get set } are merely notations. They have nothing to do with "getter and setter". They are merely ways of describing to the compiler what the protocol's requirements are. (You could argue that the notation is confusing or misleading, but it's what we've got, so we have to live with it.)
So, basically, all this says is:
An adopter must declare a name String instance property.
An adopter must also declare an age Int instance property and that property must be writable.
That's all it means. Well, you have satisfied those requirements in your adopter (Person). Your code is legal. The end.

One thing to note first: Every property has an implicit getter and setter unless otherwise stated. e.g. a simple var age: Int implicitly has a get and set, and let age: Int implicitly has a get. When you declare a manual getter and setter, you're overriding something, not creating something that didn't otherwise exist.
As for protocols, in explicit terms:
var name: String { get } means the adhering Type must have a property with a signature of name:String that can be read, AKA. get
var age: Int { get set } means the adhering Type must have a property with a signature of age:String that can be read or assigned, AKA get and set
Note that these rules are inclusive not exclusive. The requirements don't care how they are satisfied, and don't disallow anything else.
This means with your given example, a property of let name: String would work because it only requires access, but let age: Int wouldn't work, because it cannot be changed. It also doesn't care about internal details, so using computed properties, private setters, etc. is fine as long as they have the necessary access.

Related

Swift Protocols: Difference between { get } and { get set } with concrete examples?

I'm pretty new to Swift, and although I've read Apple's documentation and many topics and threads about this, I still can't understand what's the difference between { get } and { get set }. I mean, I'm looking for an explanation with a concrete example.
Like, for example:
protocol PersonProtocol {
var firstName: String { get }
var lastName: String { get set }
}
What would be the actual difference between these two properties? I tried to play with these properties in a playground:
struct Person: PersonProtocol {
var firstName: String
var lastName: String
}
var p = Person(firstName: "John", lastName: "Lennon")
print(p.firstName) // John
print(p.lastName) // Lennon
p.firstName = "Paul"
p.lastName = "McCartney"
print(p.firstName) // Paul
print(p.lastName) // McCartney
Did not help... Thanks for your help.
You are creating a variable of type Person and there are no restrictions on that struct. If you instead create a variable of type PersonProtocol then firstName will be read only
var p1: PersonProtocol = Person(firstName: "John", lastName: "Lennon")
print(p1.firstName) // John
print(p1.lastName) // Lennon
p1.firstName = "Paul" <== error: cannot assign to property: 'firstName' is a get-only property
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 a getter (accessible from outside of the type, not private), i.e. outside code should be able to read value of the property. In the implementing type it could be let 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 accessible getter and setter, i.e. outside code should be able to read and write to the property. Here only var 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.

Invalid redeclaraciton of property for protocol when base class has optional property of same name

I have a protocol that has a property name: String. I have a base class that has a property of name: String?. When I try to adopt the protocol, I keep getting invalid redeclaration error. How do I redeclare a property of the same name but optional?
protocol Targetable {
var id: String { get }
var name: String { get }
}
You cannot have several properties with the same name, but different types, so you cannot achieve what you are trying to achieve. Even if you changed the type of name of a completely unrelated type (let's say Int), you'd get the same error, this has nothing to do with one of the two declarations being Optional.

Why am I allowed to set a read only property of a protocol using a struct that inherits said protocol?

I'm following a tutorial on the protocol oriented programming paradigm in which I'm confused by something I thought was rather simple which is read only properties of protocols or getters and setters. My understanding is that a read only property is signified by using the keyword 'get' when declaring a variable within a protocol. I was excited so I quickly coded created a playground to see if my thinking was accurate however it appears that I can still change the property which I thought was read only. What am I doing wrong to make it a true read only property to where I can't set it?
protocol FullName {
var firstName: String {get set}
var lastName: String {get set}
var readOnlyProperty: String {get}
}
struct OuttaBeerOuttaHere: FullName {
var firstName: String
var lastName: String
var readOnlyProperty: String = "Jack! Jack!...Line from Titanic"
}
var leonardoDicaprio = OuttaBeerOuttaHere.init(firstName: "Leonardo", lastName: "Dicaprio", readOnlyProperty: "WTF")
print(leonardoDicaprio.readOnlyProperty) //prints "WTF"
leonardoDicaprio.readOnlyProperty = "what now"
print(leonardoDicaprio.readOnlyProperty) //prints "what now"
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.
Your protocol doesn't declare readOnlyProperty as a read-only property. It only requires that implementations of that protocol have at least gettable readOnlyProperty property. To allow mutations of that property or not is up to implementation itself.
From Docs
Here’s an example of a protocol with a single instance property requirement:
protocol FullyNamed {
var fullName: String { get }
}
The FullyNamed protocol requires a conforming type to provide a
fully-qualified name. The protocol doesn’t specify anything else about
the nature of the conforming type—it only specifies that the type must
be able to provide a full name for itself. The protocol states that
any FullyNamed type must have a gettable instance property called
fullName, which is of type String
it's a requirement from the protocol not a define

Swift, Core Data, Optional Integer16 and keyPath

I have an entity in CoreData which has an optional property of type Integer 16. It can genuinely be nil and in my application I want to refer to it as an Int? type. As Int? (or for that matter Int16?) isn't a recognised Objective-C type, the compiler throws a bit of a wobbly. I want to avoid using code like NSNumber?.intValue throughout so I've actually set up my ManagedObject type with custom accessors for this property. My question relates to identifying the property through #keyPath rather than a static string. In Core Data the field is named 'pin' on entity 'User'. Here's the code I have:
class User: NSManagedObject {
// MARK: - Properties
static let pinKey = "pin"
#NSManaged internal(set) var name: String
#NSManaged fileprivate var primitivePin: NSNumber?
internal(set) var pin: Int? {
get {
willAccessValue(forKey: #keyPath(pin)) // THIS LINE ERRORS
let value: Int? = primitivePin.map { $0.intValue }
didAccessValue(forKey: User.pinKey)
return value
}
set {
willChangeValue(forKey: User.pinKey)
primitivePin = newValue.map { NSNumber(value: Int16($0)) }
didChangeValue(forKey: User.pinKey)
}
}
}
The line in error is what I 'want' to achieve but of course the var pin isn't an obj-c type and the compiler complains, so I have defined the static constant pinKey as you can see. #keyPath feels like the right way to go about it, and the entity does have a field called pin, but in this scenario is the only option open to me to use a static value?
In #keyPath you have to specify property name. If you don't have defined property called pin, you will receive an error. In your case you have to use #keyPath(User.primitivePin). I believe this should work.
Also, i guess, calling map is redundant here. You can write directly let value = primitivePin?.intValue and so on.
The answer is....with custom properties/accessors #keyPath can't used as there is no defined #NSManaged property for it - as Maksym points out. However, you can't use the defined primitive for it either, instead using the property name as a String as also shown in the code above (User.pinKey)

Why do we use the keyword "get" in Swift variables declaration?

This might sound dumb, but I can't figure out why programmers declare variables in Swift as follows:
class Person: NSObject {
var name: String { get }
}
Why is the keyword "get" used? Why is "set" missed? I thought we used them like this:
class Person: NSObject {
var name: String {
get {
// getter
}
set {
// setter
}
}
}
This might be a spam question, but I am interested in the theoretical definition of { get }
Sentences such as var name: String { get } are normally used in protocols not in classes. In a protocol it means that the implementation must have a variable of type String which should be at least read only (hence the get). Had the curly brackets bit been { get set } the variable would have been read write.
Actually as per Earl Grey answer, var name: String { get } will not compile inside a class.
The first code example strictly speaking doesn't make sense. You do not declare variables like this in a class.. (You do it in a protocol like this.)
The second is an example of computed property,though the getter and setter implementation is missing. (it seems to be implied at least so I won't object about validity of the code example.)