web-dev-qa-db-ja.com

Swiftで遅延を発生させる方法は?

特定の時点でアプリを一時停止したい。言い換えれば、私は自分のアプリにコードを実行させたいのですが、それからある時点で、4秒間休止してから、残りのコードを続けます。これどうやってするの?

私はSwiftを使っています。

207
Schuey999

UIスレッドから呼び出された場合にプログラムをロックするスリープの代わりに、NSTimerまたはディスパッチタイマーの使用を検討してください。

しかし、現在のスレッドで本当に遅延が必要な場合は、

... {
    sleep(4)
}

これは、UNIXの sleep 関数を使用します。

219
nneonneo

dispatch_afterブロックを使用することは、スリープが実行されるスレッドが他の作業を実行することからブロックされるので、ほとんどの場合sleep(time)を使用するより良いです。 dispatch_afterを使用している場合、作業中のスレッドはブロックされないので、その間に他の作業を行うことができます。
アプリケーションのメインスレッドで作業している場合、sleep(time)を使用すると、その間UIが応答しなくなるため、アプリケーションのユーザーエクスペリエンスには適しません。

after dispatchは、スレッドをフリーズするのではなく、コードブロックの実行をスケジュールします。

Swift≥3.0

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
    // Put your code which should be executed with a delay here
})

Swift <3.0

let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
    // Put your code which should be executed with a delay here
}
290
Palle

Swift 3.0におけるさまざまなアプローチの比較

1.睡眠

このメソッドにはコールバックはありません。この行のすぐ後に4秒以内に実行されるようにコードを入れます。時間がなくなるまで、ユーザーはテストボタンのようなUI要素を繰り返すのを止めます。睡眠が始まるとボタンはちょっと凍ったように見えますが、活動インジケータのような他の要素はまだ凍らずに回転しています。あなたは睡眠中に再びこの行動を起こすことはできません。

sleep(4)
print("done")//Do stuff here

enter image description here

2.ディスパッチ、実行、そしてタイマー

これら3つのメソッドは同じように機能します。それらはすべてコールバックを使用してバックグラウンドスレッドで実行されています。構文が異なり、機能もわずかに異なります。

ディスパッチは通常、バックグラウンドスレッドで何かを実行するために使用されます。関数呼び出しの一部としてコールバックを持っています

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
    print("done")
})

Performは実際には単純化されたタイマーです。それは遅れでタイマーを設定して、そしてセレクタによって機能を引き起こします。

perform(#selector(callback), with: nil, afterDelay: 4.0)

func callback() {
    print("done")
}}

そして最後に、timerはコールバックを繰り返す機能も提供します。この場合は役に立ちません。

Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false)


func callback() {
    print("done")
}}

これら3つの方法すべてについて、ボタンをクリックしてトリガーすると、UIがフリーズすることはなく、もう一度クリックすることができます。もう一度ボタンをクリックすると、別のタイマーが設定され、コールバックが2回トリガーされます。

enter image description here

結論として

4つの方法のどれも、それだけでは十分に機能しません。 sleepはユーザーの操作を無効にするので、画面 "フリーズ"(実際にはそうではありません)が表示され、ユーザーエクスペリエンスが悪くなります。他の3つの方法では画面がフリーズすることはありませんが、何度もトリガーすることができます。ほとんどの場合、ユーザーが再度電話をかけることができるようになるまで、電話が戻るまで待ってください。

そのため、3つの非同期メソッドのうちの1つをスクリーンブロックで使用することをお勧めします。ユーザーがボタンをクリックしたときに、回転するアクティビティインジケータが上にある半透明のビューで画面全体を覆い、ボタンのクリックが処理されていることをユーザーに知らせます。その後、コールバック関数のビューとインジケータを削除し、アクションが正しく処理されたことなどをユーザーに伝えます。

38
Fangming

私はdispatch_afterを使うことが 良い選択 であることをPalleに同意します。しかし、GCDの呼び出しは書くのが面倒であるため、おそらく気に入らないでしょう。代わりに、この 便利なヘルパー を追加できます。

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

バックグラウンドスレッドでコードを遅らせる このように

delay(bySeconds: 1.5, dispatchLevel: .background) { 
    // delayed code that will run on background thread
}

メインスレッド のコードを遅らせるのはさらに簡単です。

delay(bySeconds: 1.5) { 
    // delayed code, by default run in main thread
}

Framework がより便利な機能もあるなら、HandySwiftをチェックアウトしてください。あなたはそれをあなたのプロジェクトに追加することができますCarthage または Accioそしてそれからそれを上の例のように正確に使う:

import HandySwift    

delay(by: .seconds(1.5)) { 
    // delayed code
}
30
Dschee

Swift 3でもこれを行うことができます。

そのように遅延後に機能を実行します。

override func viewDidLoad() {
    super.viewDidLoad()

    self.perform(#selector(ClassName.performAction), with: nil, afterDelay: 2.0)
}


     @objc func performAction() {
//This function will perform after 2 seconds
            print("Delayed")
        }
24

NSTimer

@ nneonneoによる答えはNSTimerを使うことを提案しましたが、それをする方法を示しませんでした。これは基本的な構文です:

let delay = 0.5 // time in seconds
NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(myFunctionName), userInfo: nil, repeats: false)

これがどのように使用される可能性があるかを示すための非常に単純なプロジェクトです。ボタンが押されると、それはタイマーをスタートさせます。タイマーは、0.5秒遅れて関数を呼び出します。

import UIKit
class ViewController: UIViewController {

    var timer = NSTimer()
    let delay = 0.5

    // start timer when button is tapped
    @IBAction func startTimerButtonTapped(sender: UIButton) {

        // cancel the timer in case the button is tapped multiple times
        timer.invalidate()

        // start the timer
        timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
    }

    // function to be called after the delay
    func delayedAction() {
        print("action has started")
    }
}

dispatch_timePalle's answer のように)を使用するのも有効な選択肢です。しかし、 キャンセルするのは難しいNSTimerを使用すると、遅延イベントが発生する前にそれをキャンセルするには、呼び出すだけです。

timer.invalidate()

sleepの使用は、特にメインスレッドではお勧めできません。スレッドで行われている作業をすべて停止するためです。

私のより完全な答えは ここ を見てください。

18
Suragch

Swift 3.0で次の実装を試してください。

func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { 
        completion()
    }
}

使用法

delayWithSeconds(1) {
   //Do something
}
6
Vakas

Swift 4.2とXcode 10.1では

あなたは延期するのに4つの方法があります。すべてのうちオプション1はしばらくしてから関数を呼び出すか実行するのが望ましいです。すべてのうちsleep()は、ほとんど使用されていません。

オプション1。

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.yourFuncHere()
}
//Your function here    
func yourFuncHere() {

}

オプション2

perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)

//Your function here  
@objc func yourFuncHere2() {
    print("this is...")
}

オプション3.

Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)

//Your function here  
@objc func yourFuncHere3() {

}

オプション4

sleep(5)
5
iOS
DispatchQueue.global(qos: .background).async {
    sleep(4)
    print("Active after 4 sec, and doesn't block main")
    DispatchQueue.main.async{
        //do stuff in the main thread here
    }
}
5
eonist

1秒未満の遅延を設定する必要がある場合は、.secondsパラメータを設定する必要はありません。これが誰かに役立つことを願っています。

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
        // your code hear
})
4
Booharin

単純な時間遅延を作成するには、Darwinをインポートしてからsleep(seconds)を使用して遅延を実行します。しかし、これには数秒しかかかりませんので、より正確な測定にはDarwinをインポートし、非常に正確な測定にはusleep(100万分の1秒)を使用できます。これをテストするために、私は書いた:

import Darwin
print("This is one.")
sleep(1)
print("This is two.")
usleep(400000)
print("This is three.")

どちらが印刷され、次に1秒間待って印刷し、次に0.4秒間待ってから印刷します。すべて正常に機能しました。

2
Ethan Wrightson

遅延機能を簡単に使うための拡張を作成することができる(Syntax:Swift 4.2+)

extension UIViewController {
    func delay(_ delay:Double, closure:@escaping ()->()) {
        DispatchQueue.main.asyncAfter(
            deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
    }
}

UIViewControllerの使い方

self.delay(0.1, closure: {
   //execute code
})
0
Hardik Thakkar

コードが既にバックグラウンドスレッドで実行されている場合は、 を使用してスレッドを一時停止します - FoundationのこのメソッドThread.sleep(forTimeInterval:)

例えば:

DispatchQueue.global(qos: .userInitiated).async {

    // Code is running in a background thread already so it is safe to sleep
    Thread.sleep(forTimeInterval: 4.0)
}

(コードがメインスレッドで実行されているときの提案については、他の回答を参照してください。)

0
Robin Stewart