Ich habe das iBook von Apple durchgesehen und konnte keine Definition dafür finden:
Kann jemand die Struktur von erklären dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Ich habe das iBook von Apple durchgesehen und konnte keine Definition dafür finden:
Kann jemand die Struktur von erklären dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Antworten:
Eine klarere Vorstellung von der Struktur:
dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)
dispatch_time_t
ist ein UInt64
. Der dispatch_queue_t
Typ ist tatsächlich mit einem Alias versehen NSObject
, aber Sie sollten nur Ihre bekannten GCD-Methoden verwenden, um Warteschlangen abzurufen . Der Block ist ein Swift-Verschluss. Insbesondere dispatch_block_t
ist definiert als () -> Void
, was äquivalent zu ist () -> ()
.
Anwendungsbeispiel:
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
print("test")
}
BEARBEITEN:
Ich empfehle die wirklich schöne delay
Funktion von @ matt .
EDIT 2:
In Swift 3 wird es neue Wrapper für GCD geben. Siehe hier: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md
Das ursprüngliche Beispiel würde in Swift 3 wie folgt geschrieben:
let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
print("test")
}
Beachten Sie, dass Sie die deadlineTime
Deklaration als schreiben DispatchTime.now() + 1.0
und das gleiche Ergebnis erhalten können, da der +
Operator wie folgt überschrieben wird (ähnlich für -
):
func +(time: DispatchTime, seconds: Double) -> DispatchTime
func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime
Dies bedeutet, dass, wenn Sie das nicht verwenden DispatchTimeInterval
enum
und nur eine Zahl schreiben, davon ausgegangen wird, dass Sie Sekunden verwenden.
dispatch_after(1, dispatch_get_main_queue()) { println("test") }
1
in dispatch_after(1, ...
kann hier viel Verwirrung stiften. Die Leute werden denken, dass es eine Anzahl von Sekunden ist, wenn es tatsächlich eine Nanosekunde ist . Ich schlage vor, die Antwort von @brindy zu lesen, wie diese Nummer richtig erstellt wird.
1
zu, dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
da dies zu Verwirrung führt. Die Leute könnten denken, dass Sie in Swift
Binary operator '+' cannot be applied to operands of type DispatchTime and '_'
auf der Linielet delayTime = DispatchTime.now() + .seconds(1.0)
DispatchTime.now() + 1.0
scheint der einzige Weg zu sein, damit es funktioniert (keine Notwendigkeit .seconds
)
Ich benutze dispatch_after
so oft, dass ich eine Dienstprogrammfunktion der obersten Ebene geschrieben habe, um die Syntax zu vereinfachen:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
Und jetzt können Sie so sprechen:
delay(0.4) {
// do stuff
}
Wow, eine Sprache, in der Sie die Sprache verbessern können. Was wäre besser?
Es scheint fast nicht wert zu sein, sich damit zu beschäftigen, nachdem sie die aufrufende Syntax verbessert haben:
func delay(_ delay:Double, closure:@escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
func delayInSec(delay: Double) -> dispatch_time_t { return dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))) }
return
. B. ).
1.0 ~~ { code...}
Swift 3+
Dies ist in Swift 3+ super einfach und elegant:
DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
// ...
}
Ältere Antwort:
Um die Antwort von Cezary zu erweitern, die nach 1 Nanosekunde ausgeführt wird, musste ich Folgendes tun, um nach 4 ½ Sekunden auszuführen.
let delay = 4.5 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), block)
Bearbeiten: Ich habe festgestellt, dass mein ursprünglicher Code leicht falsch war. Die implizite Eingabe verursacht einen Kompilierungsfehler, wenn Sie NSEC_PER_SEC nicht in ein Double umwandeln.
Wenn jemand eine optimalere Lösung vorschlagen kann, würde ich sie gerne hören.
dispatch_get_current_queue()
. Ich habe dispatch_get_main_queue()
stattdessen verwendet.
dispatch_get_main_queue()
ist definitiv das, was Sie verwenden sollten. Werde Dich auf dem Laufenden halten.
Die Syntax von matt ist sehr gut und wenn Sie den Block ungültig machen müssen, können Sie Folgendes verwenden:
typealias dispatch_cancelable_closure = (cancel : Bool) -> Void
func delay(time:NSTimeInterval, closure:()->Void) -> dispatch_cancelable_closure? {
func dispatch_later(clsr:()->Void) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(time * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), clsr)
}
var closure:dispatch_block_t? = closure
var cancelableClosure:dispatch_cancelable_closure?
let delayedClosure:dispatch_cancelable_closure = { cancel in
if closure != nil {
if (cancel == false) {
dispatch_async(dispatch_get_main_queue(), closure!);
}
}
closure = nil
cancelableClosure = nil
}
cancelableClosure = delayedClosure
dispatch_later {
if let delayedClosure = cancelableClosure {
delayedClosure(cancel: false)
}
}
return cancelableClosure;
}
func cancel_delay(closure:dispatch_cancelable_closure?) {
if closure != nil {
closure!(cancel: true)
}
}
Verwenden Sie wie folgt
let retVal = delay(2.0) {
println("Later")
}
delay(1.0) {
cancel_delay(retVal)
}
Link oben scheint unten zu sein. Original Objc Code von Github
performSelector:afterDelay:
jetzt in Swift 2 verfügbar ist, sodass Sie es abbrechen können.
dispatch_source_t
, da dies etwas ist, das Sie stornieren können).
Apple hat ein dispatch_after-Snippet für Objective-C :
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
<#code to be executed after a specified delay#>
});
Hier ist das gleiche Snippet, das auf Swift 3 portiert wurde :
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) {
<#code to be executed after a specified delay#>
}
Eine andere Möglichkeit besteht darin, Double folgendermaßen zu erweitern:
extension Double {
var dispatchTime: dispatch_time_t {
get {
return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC)))
}
}
}
Dann können Sie es so verwenden:
dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
})
Ich mag die Verzögerungsfunktion von Matt, aber aus Präferenz möchte ich lieber die Weitergabe von Schließungen einschränken.
In Swift 3.0
Versandwarteschlangen
DispatchQueue(label: "test").async {
//long running Background Task
for obj in 0...1000 {
print("async \(obj)")
}
// UI update in main queue
DispatchQueue.main.async(execute: {
print("UI update on main queue")
})
}
DispatchQueue(label: "m").sync {
//long running Background Task
for obj in 0...1000 {
print("sync \(obj)")
}
// UI update in main queue
DispatchQueue.main.sync(execute: {
print("UI update on main queue")
})
}
Versand nach 5 Sekunden
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
print("Dispatch after 5 sec")
}
Swift 3.0 Version
Führen Sie nach der Schließfunktion eine Aufgabe nach der Verzögerung im Hauptthread aus.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Nennen Sie diese Funktion wie folgt:
performAfterDelay(delay: 4.0) {
print("test")
}
1) Fügen Sie diese Methode als Teil der UIViewController-Erweiterung hinzu.
extension UIViewController{
func runAfterDelay(delay: NSTimeInterval, block: dispatch_block_t) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), block)
}
}
Rufen Sie diese Methode in VC auf:
self.runAfterDelay(5.0, block: {
//Add code to this block
print("run After Delay Success")
})
2)
performSelector("yourMethod Name", withObject: nil, afterDelay: 1)
3)
override func viewWillAppear(animated: Bool) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in
//Code Here
})
// Kompaktes Formular
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
//Code here
}
}
Obwohl dies nicht die ursprüngliche Frage des OP ist, wurden bestimmte NSTimer
verwandte Fragen als Duplikate dieser Frage markiert. Es lohnt sich daher NSTimer
, hier eine Antwort aufzunehmen.
NSTimer
vs. dispatch_after
NSTimer
ist höher, während dispatch_after
niedriger ist.NSTimer
ist einfacher abzubrechen. Zum Abbrechen dispatch_after
muss mehr Code geschrieben werden .NSTimer
Erstellen Sie eine NSTimer
Instanz.
var timer = NSTimer()
Starten Sie den Timer mit der Verzögerung, die Sie benötigen.
// invalidate the timer if there is any chance that it could have been called before
timer.invalidate()
// delay of 2 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Fügen Sie eine Funktion hinzu, die nach der Verzögerung aufgerufen werden soll (unter Verwendung des Namens, den Sie für den selector
obigen Parameter verwendet haben).
func delayedAction() {
print("Delayed action has now started."
}
timer.invalidate()
.repeats: true
.Wenn Sie ein einmaliges Ereignis haben, das nicht abgebrochen werden muss, muss die timer
Instanzvariable nicht erstellt werden. Folgendes wird ausreichen:
NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Siehe meine ausführlichere Antwort hier .
Verwenden Sie dies für mehrere Funktionen. Dies ist sehr hilfreich, um Animationen oder Activity Loader für statische Funktionen oder UI-Updates zu verwenden.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
// Call your function 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// Call your function 2
}
}
Beispiel: Verwenden Sie eine Animation, bevor eine tableView neu geladen wird. Oder ein anderes UI-Update nach der Animation.
*// Start your amination*
self.startAnimation()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
*// The animation will execute depending on the delay time*
self.stopAnimation()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
*// Now update your view*
self.fetchData()
self.updateUI()
}
}
Das hat bei mir funktioniert.
Swift 3:
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
Ziel c:
CGFloat time1 = 3.49;
CGFloat time2 = 8.13;
// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGFloat newTime = time1 + time2;
NSLog(@"New time: %f", newTime);
});
Swift 3 & 4:
Sie können eine Erweiterung für DispatchQueue erstellen und eine Funktionsverzögerung hinzufügen, die die Funktion DispatchQueue asyncAfter intern verwendet
extension DispatchQueue {
static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
let timeInterval = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure)
}
}
verwenden:
DispatchQueue.delay(.seconds(1)) {
print("This is after delay")
}
Ein weiterer Helfer zum Verzögern Ihres Codes, der zu 100% schnell verwendet wird und optional die Auswahl eines anderen Threads ermöglicht , aus dem Sie Ihren verzögerten Code ausführen können:
public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) {
let dispatchTime = DispatchTime.now() + seconds
dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}
public enum DispatchLevel {
case main, userInteractive, userInitiated, utility, background
var dispatchQueue: DispatchQueue {
switch self {
case .main: return DispatchQueue.main
case .userInteractive: return DispatchQueue.global(qos: .userInteractive)
case .userInitiated: return DispatchQueue.global(qos: .userInitiated)
case .utility: return DispatchQueue.global(qos: .utility)
case .background: return DispatchQueue.global(qos: .background)
}
}
}
Jetzt verzögern Sie einfach Ihren Code im Haupt-Thread wie folgt:
delay(bySeconds: 1.5) {
// delayed code
}
Wenn Sie Ihren Code auf einen anderen Thread verschieben möchten :
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
Wenn Sie ein Framework bevorzugen , das auch einige weitere praktische Funktionen bietet, lesen Sie HandySwift . Sie können es über Karthago zu Ihrem Projekt hinzufügen und dann genau wie in den obigen Beispielen verwenden, z.
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
Ich bevorzuge immer die Erweiterung anstelle von freien Funktionen.
Swift 4
public extension DispatchQueue {
private class func delay(delay: TimeInterval, closure: @escaping () -> Void) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
class func performAction(after seconds: TimeInterval, callBack: @escaping (() -> Void) ) {
DispatchQueue.delay(delay: seconds) {
callBack()
}
}
}
Verwenden Sie wie folgt.
DispatchQueue.performAction(after: 0.3) {
// Code Here
}
Verzögern des GCD-Aufrufs mit asyncAfter in Kürze
let delayQueue = DispatchQueue(label: "com.theappmaker.in", qos: .userInitiated)
let additionalTime: DispatchTimeInterval = .seconds(2)
Wir können als ** Mikrosekunden , Millisekunden , Nanosekunden verzögern
delayQueue.asyncAfter(deadline: .now() + 0.60) {
print(Date())
}
delayQueue.asyncAfter(deadline: .now() + additionalTime) {
print(Date())
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// ...
});
Die dispatch_after(_:_:_:)
Funktion akzeptiert drei Parameter:
eine Verzögerung
einer Versandwarteschlange
eines Blocks oder einer Schließung
Die dispatch_after(_:_:_:)
Funktion ruft den Block oder Abschluss in der Versandwarteschlange auf, der nach einer bestimmten Verzögerung an die Funktion übergeben wird. Beachten Sie, dass die Verzögerung mit der dispatch_time(_:_:)
Funktion erstellt wird. Denken Sie daran, da wir diese Funktion auch in Swift verwenden.
Ich empfehle das Tutorial Raywenderlich Dispatch Tutorial durchzugehen
Verwenden Sie in Swift 5 Folgendes:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: closure)
// time gap, specify unit is second
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
Singleton.shared().printDate()
}
// default time gap is second, you can reduce it
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
// just do it!
}
Verwenden Sie diesen Code, um nach 2,0 Sekunden eine UI-bezogene Aufgabe auszuführen.
let delay = 2.0
let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
let mainQueue = dispatch_get_main_queue()
dispatch_after(delayInNanoSeconds, mainQueue, {
print("Some UI related task after delay")
})
Swift 3.0 Version
Führen Sie nach der Schließfunktion eine Aufgabe nach der Verzögerung im Hauptthread aus.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Nennen Sie diese Funktion wie folgt:
performAfterDelay(delay: 4.0) {
print("test")
}
Jetzt mehr als syntaktischer Zucker für asynchrone Versendungen in Grand Central Dispatch (GCD) in Swift.
Podfile hinzufügen
pod 'AsyncSwift'
Dann können Sie es so verwenden.
let seconds = 3.0
Async.main(after: seconds) {
print("Is called after 3 seconds")
}.background(after: 6.0) {
print("At least 3.0 seconds after previous block, and 6.0 after Async code is called")
}
Swift 4 hat eine ziemlich kurze Möglichkeit, dies zu tun:
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
// Your stuff here
print("hello")
}
Hier ist die synchrone Version von asyncAfter in Swift:
let deadline = DispatchTime.now() + .seconds(3)
let semaphore = DispatchSemaphore.init(value: 0)
DispatchQueue.global().asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
semaphore.signal()
}
semaphore.wait()
Zusammen mit asynchronen:
let deadline = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
}