Tôi đã xem qua iBook từ Apple và không thể tìm thấy bất kỳ định nghĩa nào về nó:
Ai đó có thể giải thích cấu trúc của dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Tôi đã xem qua iBook từ Apple và không thể tìm thấy bất kỳ định nghĩa nào về nó:
Ai đó có thể giải thích cấu trúc của dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Câu trả lời:
Một ý tưởng rõ ràng hơn về cấu trúc:
dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)
dispatch_time_t
là một UInt64
. Kiểu dispatch_queue_t
thực sự được đặt bí danh cho một NSObject
, nhưng bạn chỉ nên sử dụng các phương thức GCD quen thuộc của mình để nhận hàng đợi. Các khối là một đóng cửa Swift. Cụ thể, dispatch_block_t
được định nghĩa là () -> Void
, tương đương với () -> ()
.
Ví dụ sử dụng:
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
print("test")
}
BIÊN TẬP:
Tôi khuyên bạn nên sử dụng chức năng thực sự tốt đẹp của @ mattdelay
.
EDIT 2:
Trong Swift 3, sẽ có các hàm bao mới cho GCD. Xem tại đây: https://github.com/apple/swift-evolution/blob/master/proposeals/0088-libdispatch-for-swift3.md
Ví dụ ban đầu sẽ được viết như sau trong Swift 3:
let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
print("test")
}
Lưu ý rằng bạn có thể viết deadlineTime
khai báo dưới dạng DispatchTime.now() + 1.0
và nhận được kết quả tương tự vì +
toán tử bị ghi đè như sau (tương tự cho -
):
func +(time: DispatchTime, seconds: Double) -> DispatchTime
func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime
Điều này có nghĩa là nếu bạn không sử dụng DispatchTimeInterval
enum
và chỉ viết một số, có thể giả định rằng bạn đang sử dụng giây.
dispatch_after(1, dispatch_get_main_queue()) { println("test") }
1
trong dispatch_after(1, ...
có thể gây ra nhiều nhầm lẫn ở đây. Mọi người sẽ nghĩ đó là một vài giây, khi nó thực sự là nano giây . Tôi đề nghị xem câu trả lời của @brindy về cách tạo số này đúng cách.
1
để dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
vì nó dẫn đến sự nhầm lẫn. Mọi người có thể nghĩ rằng bạn không cần phải tạo một
Binary operator '+' cannot be applied to operands of type DispatchTime and '_'
trên đường dâylet delayTime = DispatchTime.now() + .seconds(1.0)
DispatchTime.now() + 1.0
dường như là cách duy nhất để làm cho nó hoạt động (không cần .seconds
)
Tôi sử dụng dispatch_after
thường xuyên đến nỗi tôi đã viết một hàm tiện ích cấp cao nhất để làm cho cú pháp đơn giản hơn:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
Và bây giờ bạn có thể nói như thế này:
delay(0.4) {
// do stuff
}
Wow, một ngôn ngữ mà bạn có thể cải thiện ngôn ngữ. Những gì có thể tốt hơn?
Có vẻ như không đáng bận tâm, bây giờ họ đã cải thiện cú pháp gọi:
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
).
1.0 ~~ { code...}
Swift 3+
Điều này cực dễ và thanh lịch trong Swift 3+:
DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
// ...
}
Trả lời cũ hơn:
Để mở rộng câu trả lời của Cezary, sẽ thực hiện sau 1 nano giây, tôi đã phải làm như sau để thực hiện sau 4 giây rưỡi.
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)
Chỉnh sửa: Tôi phát hiện ra rằng mã ban đầu của tôi là hơi sai. Gõ ngầm định gây ra lỗi biên dịch nếu bạn không chuyển NSEC_PER_SEC thành Double.
Nếu bất cứ ai có thể đề xuất một giải pháp tối ưu hơn, tôi rất muốn nghe nó.
dispatch_get_current_queue()
. Tôi đã sử dụng dispatch_get_main_queue()
thay thế.
dispatch_get_main_queue()
chắc chắn là những gì bạn nên sử dụng. Sẽ nâng cấp.
Cú pháp của matt rất hay và nếu bạn cần làm mất hiệu lực khối, bạn có thể muốn sử dụng:
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)
}
}
Sử dụng như sau
let retVal = delay(2.0) {
println("Later")
}
delay(1.0) {
cancel_delay(retVal)
}
Liên kết ở trên dường như được xuống. Mã Objc gốc từ Github
performSelector:afterDelay:
hiện đã có trong Swift 2, vì vậy bạn có thể hủy nó.
dispatch_source_t
hủy dựa trên GCD (sử dụng một , vì đó là thứ bạn có thể hủy).
Apple có một đoạn công văn sau khi chọn 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#>
});
Đây là đoạn trích tương tự được chuyển sang Swift 3:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) {
<#code to be executed after a specified delay#>
}
Một cách khác là mở rộng gấp đôi như thế này:
extension Double {
var dispatchTime: dispatch_time_t {
get {
return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC)))
}
}
}
Sau đó, bạn có thể sử dụng nó như thế này:
dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
})
Tôi thích chức năng trì hoãn của matt nhưng không được ưu tiên. Tôi muốn hạn chế việc đóng cửa xung quanh.
Trong Swift 3.0
Công văn xếp hàng
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")
})
}
Công văn sau 5 giây
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
print("Dispatch after 5 sec")
}
Phiên bản Swift 3.0
Sau chức năng đóng thực thi một số tác vụ sau khi trì hoãn trên luồng chính.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Gọi hàm này như sau:
performAfterDelay(delay: 4.0) {
print("test")
}
1) Thêm phương thức này như là một phần của Phần mở rộng UIViewControll.
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)
}
}
Gọi phương thức này trên VC:
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
})
// Mẫu nhỏ gọn
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
//Code here
}
}
Mặc dù không phải là câu hỏi ban đầu của OP, một số NSTimer
câu hỏi liên quan đã được đánh dấu là trùng lặp của câu hỏi này, vì vậy nó có giá trị bao gồm một NSTimer
câu trả lời ở đây.
NSTimer
đấu với dispatch_after
NSTimer
là cấp cao hơn trong khi dispatch_after
cấp thấp hơn.NSTimer
dễ dàng hơn để hủy bỏ. Hủy bỏ dispatch_after
yêu cầu viết thêm mã .NSTimer
Tạo một NSTimer
ví dụ.
var timer = NSTimer()
Bắt đầu hẹn giờ với độ trễ mà bạn cần.
// 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)
Thêm một hàm được gọi sau độ trễ (sử dụng bất kỳ tên nào bạn đã sử dụng cho selector
tham số ở trên).
func delayedAction() {
print("Delayed action has now started."
}
timer.invalidate()
.repeats: true
.Nếu bạn có một sự kiện một lần mà không cần phải hủy thì không cần phải tạo timer
biến thể hiện. Sau đây sẽ đủ:
NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Xem câu trả lời đầy đủ hơn của tôi ở đây .
Đối với nhiều chức năng sử dụng này. Điều này rất hữu ích để sử dụng hình động hoặc Trình tải hoạt động cho các chức năng tĩnh hoặc bất kỳ Cập nhật giao diện người dùng nào.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
// Call your function 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// Call your function 2
}
}
Ví dụ: Sử dụng hình động trước khi tải lại bảngView. Hoặc bất kỳ cập nhật giao diện người dùng khác sau khi hình ảnh động.
*// 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()
}
}
Điều này làm việc cho tôi.
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)")
}
Mục tiêu-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:
Bạn có thể tạo tiện ích mở rộng trên DispatchQueue và thêm chức năng trì hoãn sử dụng chức năng DispatchQueue asyncAfter trong nội bộ
extension DispatchQueue {
static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
let timeInterval = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure)
}
}
sử dụng:
DispatchQueue.delay(.seconds(1)) {
print("This is after delay")
}
Một người trợ giúp khác để trì hoãn mã của bạn là 100% Swift trong sử dụng và tùy chọn cho phép chọn một luồng khác để chạy mã bị trì hoãn của bạn từ:
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)
}
}
}
Bây giờ bạn chỉ cần trì hoãn mã của mình trên luồng chính như thế này:
delay(bySeconds: 1.5) {
// delayed code
}
Nếu bạn muốn trì hoãn mã của mình sang một luồng khác :
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
Nếu bạn thích một Framework cũng có một số tính năng tiện dụng hơn thì hãy kiểm tra HandySwift . Bạn có thể thêm nó vào dự án của mình thông qua Carthage sau đó sử dụng chính xác như trong các ví dụ trên, ví dụ:
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
Tôi luôn thích sử dụng phần mở rộng thay vì các chức năng miễn phí.
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()
}
}
}
Sử dụng như sau.
DispatchQueue.performAction(after: 0.3) {
// Code Here
}
Trì hoãn cuộc gọi GCD bằng asyncSau khi nhanh chóng
let delayQueue = DispatchQueue(label: "com.theappmaker.in", qos: .userInitiated)
let additionalTime: DispatchTimeInterval = .seconds(2)
Chúng ta có thể trì hoãn dưới dạng ** micro giây , mili giây , nano giây
delayQueue.asyncAfter(deadline: .now() + 0.60) {
print(Date())
}
delayQueue.asyncAfter(deadline: .now() + additionalTime) {
print(Date())
}
Trong Swift 4
Sử dụng đoạn mã này:
let delayInSec = 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + delayInSec) {
// code here
print("It works")
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// ...
});
Các dispatch_after(_:_:_:)
chức năng có ba thông số:
một sự chậm trễ
một công văn xếp hàng
một khối hoặc đóng cửa
Các dispatch_after(_:_:_:)
chức năng gọi khối hay đóng cửa trên hàng đợi công văn được truyền cho hàm sau khi một sự chậm trễ nhất định. Lưu ý rằng độ trễ được tạo bằng dispatch_time(_:_:)
hàm. Hãy nhớ điều này bởi vì chúng tôi cũng sử dụng chức năng này trong Swift.
Tôi khuyên bạn nên xem qua hướng dẫn Raywenderlich Dispatch hướng dẫn
Trong Swift 5, sử dụng ở bên dưới:
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!
}
sử dụng mã này để thực hiện một số tác vụ liên quan đến giao diện người dùng sau 2,0 giây.
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")
})
Phiên bản Swift 3.0
Sau chức năng đóng thực thi một số tác vụ sau khi trì hoãn trên luồng chính.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Gọi hàm này như sau:
performAfterDelay(delay: 4.0) {
print("test")
}
Bây giờ nhiều hơn đường cú pháp cho các công văn không đồng bộ trong Grand Central Dispatch (GCD) trong Swift.
thêm Podfile
pod 'AsyncSwift'
Sau đó, bạn có thể sử dụng nó như thế này.
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")
}
Đây là phiên bản đồng bộ của asyncSfter trong 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()
Cùng với một không đồng bộ:
let deadline = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
}