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.)
Related
I have been trying to find an answer to understand the "under the hook" or "technicalities" on whether or not the following code should be or not be avoided:
protocol Member {
var id: String: { get }
var name: String { get }
}
protocol RegularMember: Member {
var name: String { get }
...
}
RegularMember declares the same property name that Member also declares.
I have had this question always in my head and always assumed that it was bad practice but never got further than that.
Does anyone have different thoughts?
However, Xcode is not showing neither a warning nor an error.
Because it isn't wrong for protocol B that conforms to protocol A to repeat requirements from protocol A. Quite the contrary! It doesn't change the meaning of anything, and in fact, it's good practice stylistically because it can make your code more readable; the Swift Standard Library does it a lot.
When I create a function in Swift, can I use "get" and "set" words? For instance can I declare a function as func getAuthorizedUsers() instead of func authorizedUsers()? In ObjectiveC get and set keywords are not suggested to use when declaring functions. How about in Swift?
Also, when declaring properties can I use "is" keyword? For instance:
public var isAuthorized: Bool {
get {
return true
}
}
I have read Swift naming convention documents but I couldn't find the answer of my question. Thank you.
The rules are all outlined here.
For get, that clearly violates the "Omit needless words" rule. If a method returns something, the call site will know that it is used to get some value. You don't need to repeat that idea. You can consider turning this into a computed property if no parameters are required.
For set, it might be appropriate sometimes. If your method only need one parameter and there is a corresponding getter,
func getFoo() -> Int {
...
}
func setFoo(_ foo: Int) {
...
}
That's a pretty good sign that this can be turned into a computed property:
var foo: Int {
get { ... }
set { ... }
}
A good example where it is appropriate to have set is the UIButton.setTitle method. It takes in two parameters, so a computed property wouldn't work.
For is, that clearly conforms to the rule "Uses of Boolean methods and properties should read as assertions about the receiver". So yes, you should use it for boolean members.
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.
Is there a difference between a getter computed property and variable that returns a value? E.g. is there a difference between the following two variables?
var NUMBER_OF_ELEMENTS1: Int {
return sampleArray.count
}
var NUMBER_OF_ELEMENTS2: Int {
get {
return sampleArray.count
}
}
A computer property with getter and setter has this form:
var computedProperty: Int {
get {
return something // Implementation can be something more complicated than this
}
set {
something = newValue // Implementation can be something more complicated than this
}
}
In some cases a setter is not needed, so the computed property is declared as:
var computedProperty: Int {
get {
return something // Implementation can be something more complicated than this
}
}
Note that a computed property must always have a getter - so it's not possible to declare one with a setter only.
Since it frequently happens that computed properties have a getter only, Swift let us simplify their implementation by omitting the get block, making the code simpler to write and easier to read:
var computedProperty: Int {
return something // Implementation can be something more complicated than this
}
Semantically there's no difference between the 2 versions, so whichever you use, the result is the same.
They are identical since both define a read-only computed property. But the former is preferable because it is shorter and more readable than the latter.
While migrating some projects from Objective-C to Swift, I find myself replacing the #property/#synthesize syntax with a lot more boiler-plate code.
For example, for every #property I am implementing, I currently use this pattern:
var foo: Foo? {
get {
return _foo
}
set {
_foo = newValue
}
}
var _foo: Foo?
It ends up adding quickly. Compare this with the 2 lines in Objective-C. That doesn't feel right.
Should I just replace the code using _foo in my ported classes with foo and skip the abstraction of each public var behind an interface entirely?
As #Amit89 pointed out, you can simply use _foo.
In your example, adding foo does exactly nothing, as you simply recreated the get and set functionality already supplied with _foo.
If you want to control how _foo is set you can use property observers:
var _foo: Foo? {
didSet { }
willSet { }
}
If you want to control how _foo is retrieved, then it would indeed make sense to create a private version of _foo, and then accessing it via a computed property:
private var _foo: Foo?
var foo: Foo? {
get {
// return `_foo` in some special way
}
// add a setter if you want to set `_foo` in some special way
}