Let's say I have a class named Person
, with variables like firstName
and lastName
. I am listening to changes in these variables using a reactiveCocoa-framework, but let's say I'm only using the built in KVO-listening, like the didSet{}
. So assume I have this code:
let firstName:String { didSet{ self.nameDidChange() }}
let lastName: String { didSet{ self.nameDidChange() }}
func nameDidChange(){ print("New name:", firstName, lastName}
Every time I'd change either the first name or the last name, it would automatically call the function nameDidChange
.
What I'm wondering, is if there's any smart move here to prevent the nameDidChange
function from being called twice in a row when I change both the firstName
and the lastName
.
Let's say the value in firstName
is "Anders"
and lastName
is "Andersson"
, then I run this code:
firstName = "Borat"
lastName = "Boratsson"
nameDidChange
will be called twice here. It will first print out "New name: Borat Andersson"
, then "New name: Borat Boratsson"
.
In my simple mind, I'm thinking I can create a function called something like nameIsChanging()
, call it whenever any of the didSet
is called, and start a timer for like 0.1 second, and then call nameDidChange()
, but both of these didSet
s will also call nameIsChanging
, so the timer will go twice, and fire both times. To solve this, I could keep a "global" Timer
, and make it invalidate itself and restart the count or something like that, but the more I think of solutions, the uglier they get. Are there any "best practices" here?
To delay a function call, use setTimeout() function. functionname − The function name for the function to be executed. milliseconds − The number of milliseconds. arg1, arg2, arg3 − These are the arguments passed to the function.
You can use JavaScript Timing Events to call function after certain interval of time: This shows the alert box every 3 seconds: setInterval(function(){alert("Hello")},3000); You can use two method of time event in javascript.
I think you are on the right track. I think you just need to delay the call to name changed until the user has "Stopped" typing.
Something like this:
var timer = Timer()
var firstName: String = "Clint" {
didSet {
timer.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false, block: { _ in
self.nameDidChange()
})
}
}
var secondName: String = "Eastwood" {
didSet {
timer.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false, block: { _ in
self.nameDidChange()
})
}
}
func nameDidChange() {
print(firstName + secondName)
}
Everytime the first or second name is changed it will stop the timer and wait another 0.2 seconds until it commits the name change.
Edit
After reading the comment by Adam Venturella I realized that it is indeed a debouncing technique. It would be useful to google the concept if you would like to learn some more about it.
Here is a simple Playground that illustrates the concept:
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var timer: Timer? = nil
func nameDidChange() {
print("changed")
}
func debounce(seconds: TimeInterval, function: @escaping () -> Swift.Void ) {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: seconds, repeats: false, block: { _ in
function()
})
}
debounce(seconds: 0.2) { nameDidChange() }
debounce(seconds: 0.2) { nameDidChange() }
debounce(seconds: 0.2) { nameDidChange() }
debounce(seconds: 0.2) { nameDidChange() }
debounce(seconds: 0.2) { nameDidChange() }
debounce(seconds: 0.2) { nameDidChange() }
The output:
changed
The nameDidChange function was executed only once.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With