Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for a given time and only perform last function call

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 didSets 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?

like image 794
Sti Avatar asked Nov 07 '17 17:11

Sti


People also ask

How do I add a delay to a function call?

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.

How do you cause a function to be invoked at a specified time later?

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.


1 Answers

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.

like image 90
Nordeast Avatar answered Oct 31 '22 23:10

Nordeast