2017-11-07 199 views
5

firstName ve lastName gibi değişkenlerle Person adında bir sınıfımız olduğunu varsayalım. Bu değişkenlerdeki değişiklikleri bir reaktifCocoa-framework kullanarak dinliyorum, fakat diyelim ki sadece didSet{} gibi KVO dinlemede yerleşik yapıyorum.Belirli bir süre bekleyip yalnızca son işlev çağrısı gerçekleştiriliyor

let firstName:String { didSet{ self.nameDidChange() }} 
let lastName: String { didSet{ self.nameDidChange() }} 

func nameDidChange(){ print("New name:", firstName, lastName} 

Ben ilk adını veya soyadını ya değiştirecek her zaman, otomatik olarak işlevini nameDidChange çağırır: Ben bu kod var varsayalım. Ne merak ediyorum,işlevinin firstName ve lastName her ikisini de değiştirdiğimde üst üste iki kez çağrılmasını önlemek için herhangi bir akıllı hareket var mıdır.

sonra bu kodu çalıştırmak, en firstName değeri "Anders" ve lastName "Andersson" olduğunu varsayalım: Burada iki kez

firstName = "Borat" 
lastName = "Boratsson" 

nameDidChange çağrılır. Önce "New name: Borat Andersson", sonra "New name: Borat Boratsson" yazdıracaktır. Benim basit zihninde

, ben didSet herhangi çağrıldığında diyoruz ve benzeri 0,1 saniye bir zamanlayıcı başlatmak, nameIsChanging() gibi bir şey adlı bir işlev oluşturabilir düşünme ve sonra çağrı nameDidChange() ama değilim Bu didSet s her ikisi de nameIsChanging arayacak, böylece zamanlayıcı iki kez gidecek ve iki kere ateş. Bunu çözmek için, bir "global" Timer'u saklayabilir ve onu geçersiz kılabilir ve sayımı veya benzeri bir şeyi yeniden başlatabilirim, ancak çözümlerin ne kadar çok olduğunu düşünürler. Burada "en iyi uygulamalar" var mı?

+0

Varsayılan olarak "false" olan bir "Boole" isChangingName "ve" nameDidChange "içinde bu şekilde ayarlayın, daha sonra" nameIsChanging "," false "olduğundan emin olmak için bir" guard "kullanabilir. 've sonra bir zamanlayıcı ile gecikmeli çalışmayı başlatın ya da '' (:, afterDelay: ile) gerçekleştirin. – theMikeSwan

+0

Bence yapay bir gecikme ekleyerek, kullanıcı bunu" yavaş "veya bağlantısız hissettirebilir. İşlevi çağırmayı geciktirmeye gerçekten ihtiyaç var mı? Gecikme rotasına giderseniz, uygulamanın bir şeyler yaptığını * görsel * belirtmeniz gerekir. – Zig

+0

@Zig ​​Aynı anda ayarlanacağından, bunu önlemek için yalnızca 0,01 saniye gecikmeye ihtiyacım var. Bu sadece programatik olarak aynı zamanda ayarlandığında geçerlidir. Bunun yanı sıra, ayrı ayrı da değiştirildiyse, fonksiyonu çağırmaları için onlara ihtiyacım var. İhtiyaç duyulmadığında her birinin bir url isteğini tetiklemesi önlenir. – Sti

cevap

1

Sanırım doğru yoldasınız. Ben sadece kullanıcı "Durdu" yazarak kadar değişti adı için çağrıyı geciktirmek gerektiğini düşünüyorum. Böyle

şey:

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 birinci veya ikinci isim o Sayacı durdurmak ve ad değişikliği taahhüt kadar başka 0.2 saniye bekler değiştirilir.

Düzenleme

Adam Venturella tarafından yorumunu okuduktan sonra ben gerçekten zıplamaölçer tekniğidir fark etti. Bu konuda daha fazla bilgi edinmek istiyorsanız, Google’ın konsepti için yararlı olacaktır.

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() } 

çıktı:

changed 

nameDidChange fonksiyonu sadece bir kez çalıştırıldı İşte

kavramı gösterir basit Bahçesi olduğunu.

+1

Bir yüze isim vermek için bir isim koymak, bu tekniğe “çözülme” denir –

0

Sorunuzu doğru bir şekilde anladığımdan emin değilim, ancak zamanlayıcılar yerine, birbirlerinin peşinden koşup çıkmadıklarını görmek için Date'u kullanmayı deneyebilirsiniz. Ayrıca, .timeIntervalSince1970'un 1970'den beri geçen saniye sayısını döndürdüğünden, daha iyi bir hassasiyet elde etmek için 100 ile çarptığımı unutmayın.

var firstName:String! { didSet{ self.nameDidChange() }} 
var lastName: String! { didSet{ self.nameDidChange() }} 

var currentDate: UInt64 = UInt64((Date().timeIntervalSince1970 * 100)) - 100 

func nameDidChange(){ 
    let now = UInt64(Date().timeIntervalSince1970 * 100) 
    //You can add a higher tolerance here if you wish 
    if (now == currentDate) { 
     print("firing in succession") 
    } else { 
     print("there was a delay between the two calls") 
    } 
    currentDate = now 
} 

DÜZENLEME: Bu son aramanın daha ziyade birinci çağrı ama belki bu yardımcı olabilir çalışmaz rağmen/bazı fikirler

0

nameDidChange() çağrıları birleşmeye kolay bir şekilde kıvılcım aracılığıyla çağırmaktır; Bu arama beklemede değilse, DispatchQueue.main.async.

class MyObject { 
    var firstName: String = "" { didSet { self.scheduleNameDidChange() } } 
    var lastName: String = "" { didSet { self.scheduleNameDidChange() } } 

    private func scheduleNameDidChange() { 
     if nameDidChangeIsPending { return } 
     nameDidChangeIsPending = true 
     RunLoop.main.perform { self.nameDidChange() } 
    } 

    private func nameDidChange() { 
     nameDidChangeIsPending = false 
     print("New name:", firstName, lastName) 
    } 

    private var nameDidChangeIsPending = false 
} 

tek UI olayı (örneğin bir dokunuş) firstName ve lastName, nameDidChange() birden çok değişiklik ile sonuçlanırsa o

yalnızca bir kez olarak adlandırılır.