How do you implement setter without getter in Swift? I need to call a method when the value is set:
var selectedIndex : Int{
set {
selectItemAtIndex(newValue)
}
}
but in Swift, you are required to use both getter and setter, not just one.
You can use the property observer didSet. This will be called immediately after setting the value.
var selectedIndex: Int {
didSet {
selectItemAtIndex(selectedIndex)
}
}
Related
To do KVO in Swift, you make a NSObject-based #objc class, and can observe properties that are stored and marked #objc and dynamic.
Can you observe on computed properties (that are #objc and dynamic)?
I just glanced at the Objective-C guide, and it showed you could mark KVO dependencies for a computed property. And (I think) observe on an array property changing at the element level. Can either of those be done in Swift?
You asked:
Can you observe on computed properties (that are #objc and dynamic)?
Yes. Just mark your computed property #objc and dynamic and when the setter for the computed property is called, then the observer will be called.
For example, consider a synchronizer class, where you want to observe the computed property, value :
class Synchronized: NSObject {
private var _value: Int
private let queue = DispatchQueue(label: "synchronizer", attributes: .concurrent)
init(value: Int) {
_value = value
super.init()
}
#objc dynamic var value: Int {
get { queue.sync { _value } }
set { queue.async(flags: .barrier) { self._value = newValue} }
}
}
Here, the value is a computed variable, which you can set and all the usual KVO can take place:
token = foo.observe(\.value, options: .new) { _, change in
print(change.newValue ?? "Unknown")
}
This observer is triggered when the value setter is called.
The only trick is going to be if you want the KVO triggered notification if the the value returned by the computed property changes via something other than the computed property’s setter. In that case, you’d have to manually issue the KVO notifications.
Can anyone explain the behaviour when subclassing properties? I am sure there is a good explanation for why 'override' does not actually override the property.
Why does Swift allow the surname property to be overridden but apparently still uses the super class's property and associated functions? They are not overridden.
It would seem that I would have to define some function that gets called in the didSet() method and override that to ensure the subclass does not inherit the super class's function as with the telephone property.
Is there any way to override a property's didSet() method? Creating some function that gets called seems to add an unnecessary extra complexity?
What is the correct way of achieving this?
import Cocoa
class BaseClass {
var _name: String?
var name: String? {
get {
return _name
}
set {
_name = newValue
print("BaseClass \(name)")
}
}
var surname: String? {
didSet {
print("BaseClass \(surname)")
}
}
var telephone: String? {
didSet {
telephoneSet()
}
}
func telephoneSet(){
print("BaseClass \(telephone)")
}
}
class SubClass: BaseClass {
override var name: String? {
get {
return _name
}
set {
_name = newValue
print("SubClass \(name)")
}
}
override var surname: String? {
didSet {
print("SubClass \(surname)")
}
}
override func telephoneSet(){
print("SubClass \(telephone)")
}
}
let object = SubClass()
object.name = "Jenny"
object.surname = "Jones"
object.telephone = "10810"
Generates the following output:
SubClass Optional("Jenny")
BaseClass Optional("Jones")
SubClass Optional("Jones")
SubClass Optional("10810")
Let’s reduce the example:
class BaseClass {
var surname: String? {
didSet { print("BaseClass \(surname)") }
}
}
class SubClass: BaseClass {
override var surname: String? {
didSet { print("SubClass \(surname)") }
}
}
Then:
let object = SubClass()
object.surname = "Jones"
Will produce:
BaseClass Optional("Jones")
SubClass Optional("Jones")
The above is not overriding the stored property, surname, with another stored property. There is only the stored property of the base class and the subclass is simply adding its own observer to this property. I refer you to The Swift Programming Language: Inheritance: Overriding, which says:
Overriding Property Observers
You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of an inherited property changes, regardless of how that property was originally implemented.
In your example of name, you are overriding the computed property with the subclasses’ own computed property. Likewise, in your example of telephoneSet, you are also overriding the method with the subclasses’ own method. But with surname, you’re not overriding the base classes’ property, but merely letting the subclass add an observer to the base classes’ stored property.
I have a simple class below
import Foundation
public class UsefulClass: NSObject{
var test:NSNumber{
get{return self.test}
set{
println(newValue)
self.test = newValue
}
}
override init() {
super.init()
self.test = 5;
}
}
and I'm initializing it here
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var testClass = UsefulClass()
}
}
But it results in xcode printing out 200 5s and then crashing due to EXC_BAD_ACCESS code = 2. Why does this happen?
#vadian has provided a solution in his answer, which should fix your problem. Let me just explain what's happening.
You have created a computed property, i.e. a property which is not backed by a variable, instead both the getter and the setter do some processing, usually on another stored property, in order to respectively return a value and set a new value.
This is your computed property:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Look at the getter implementation:
return self.test
What does it do? It reads the test property of the current instance, and returns it. Which is the test property? It's this one:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Yes, it's the same property. What your getter does is to recursively and indefinitely calling itself, until a crash happen at runtime.
The same rule applies to the setter:
self.test = newValue
it keeps invoking itself, until the app crashes.
Swift variables are synthesized properties by default.
In the most cases this is sufficient (it's recommended to prefer Swift types)
var test: Int
override init() {
super.init()
test = 5
}
If you need to do something after a variable is set, use
var test: Int {
didSet{
println("\(oldValue) - \(newValue)")
}
}
your code sets the variable permanently by calling the setter which calls the setter which …
It's an infinite loop; your setter is recursively calling itself.
var test: NSNumber {
set {
test = newValue
}
}
This compiles fine, and an Objective-C programmer might expect no loop due to instead setting a "backing ivar" such as _test rather than re-calling the setter method.
But property-backing instance variable _ivars do not exist in Swift for computed properties unless you create them yourself.
I’ve got a car and a driver. They mutually reference each other. In the car’s init() I create a driver and assign it to the driver member. The driver member has a didSet method which is supposed to set the driver’s car, thus mutually link them to each other.
class GmDriver {
var car: GmCar! = nil
}
class GmCar {
var driver: GmDriver {
didSet {
driver.car = self
}
}
init() {
driver = GmDriver()
}
}
let myCar = GmCar()
println(myCar.driver.car) // nil
However, the didSet never fires. Why?
Apple Documentation:
The willSet and didSet observers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They are not called while a class is setting its own properties, before the superclass initializer has been called.
init() {
defer {
driver = GmDriver()
}
}
Is there an ivar property we should use in a Swift getter? My code is causing the getter to call the getter until the program crashes:
var document: UIDocument? {
get {
return self.document
}
set {
self.document = newValue
useDocument()
}
}
Swift properties do not have the concept of separate, underlying storage like they do in Objective-C. Instead, you'll need to create a second (private) property and use that as the storage:
private var _document: UIDocument?
var document: UIDocument? {
get {
return _document
}
set {
_document = newValue
useDocument()
}
}
If all you're trying to do is call useDocument() after the document property is set, you can omit the getter, setter, and private property and instead just use willSet or didSet.
If what you are trying to achieve is add some custom processing when the property is set, you don't need to define a separate backing data member and implement a computed property: you can use the willSet and didSet property observers, which are automatically invoked respectively before and after the property has been set.
In your specific case, this is how you should implement your property:
var document: UIDocument? {
didSet {
useDocument()
}
}
Suggested reading: Property Observers
In your code there is an infinite recursion situation: for example, self.document inside the getter keep calling the getter itself.
You need to explicitly define an ivar yourself. Here is a possible solution:
private var _document:UIDocument?
var document: UIDocument? {
get {
return self._document
}
set {
self._document = newValue
useDocument()
}
}