web-dev-qa-db-ja.com

バックグラウンドスレッドを迅速に使用する方法

迅速にスレッドを使用する方法?

dispatchOnMainThread:^{

    NSLog(@"Block Executed On %s", dispatch_queue_get_label(dispatch_get_current_queue()));

}];
278
Anshul

Swift 3.0以降

Swift 3.0ではたくさんのことが 近代化 されています。バックグラウンドスレッドで何かを実行すると、次のようになります。

DispatchQueue.global(qos: .background).async {
    print("This is run on the background queue")

    DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
    }
}

Swift 1.2から2.3

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
    print("This is run on the background queue")

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        print("This is run on the main queue, after the previous code in outer block")
    })
})

Pre Swift 1.2 - 既知の問題

Swift 1.1以降、Appleは上記の構文を変更せずにサポートしませんでした。 QOS_CLASS_BACKGROUNDを渡すことは実際にはうまくいきませんでした、代わりにInt(QOS_CLASS_BACKGROUND.value)を使います。

詳細については リンゴのドキュメント を参照してください。

641
tobiasdm

ベストプラクティスは、複数回アクセスできる再利用可能な関数を定義することです。

使用可能な機能:

例えばグローバル関数としてのAppDelegate.Swiftのような場所。

func backgroundThread(_ delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) {
    dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
        background?()

        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
        dispatch_after(popTime, dispatch_get_main_queue()) {
            completion?()
        }
    }
}

注:Swift 2.0では、代わりに QOS_CLASS_USER_INITIATED.value QOS_CLASS_USER_INITIATED.rawValue に置き換えてください。

使用法:

A.バックグラウンドで3秒遅れてプロセスを実行するには

    backgroundThread(3.0, background: {
            // Your background function here
    })

B.バックグラウンドでプロセスを実行するには、フォアグラウンドで完了を実行します。

    backgroundThread(background: {
            // Your function here to run in the background
    },
    completion: {
            // A function to run in the foreground when the background thread is complete
    })

C. 3秒遅らせる - バックグラウンドパラメータなしで完了パラメータを使用することに注意してください。

    backgroundThread(3.0, completion: {
            // Your delayed function here to be run in the foreground
    })
115
Dale Clifford

Swift5でのDan Beaulieuの答え(Swift 3.0.1以降でも機能します)。

Swift 5.0.1

extension DispatchQueue {

    static func background(delay: Double = 0.0, background: (()->Void)? = nil, completion: (() -> Void)? = nil) {
        DispatchQueue.global(qos: .background).async {
            background?()
            if let completion = completion {
                DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: {
                    completion()
                })
            }
        }
    }

}

使用法

DispatchQueue.background(delay: 3.0, background: {
    // do something in background
}, completion: {
    // when background job finishes, wait 3 seconds and do something in main thread
})

DispatchQueue.background(background: {
    // do something in background
}, completion:{
    // when background job finished, do something in main thread
})

DispatchQueue.background(delay: 3.0, completion:{
    // do something in main thread after 3 seconds
})
44
frouo

Swift 3バージョン

Swift 3は新しいDispatchQueueクラスを利用してキューとスレッドを管理します。バックグラウンドスレッドで何かを実行するには、次のようにします。

let backgroundQueue = DispatchQueue(label: "com.app.queue", qos: .background)
backgroundQueue.async {
    print("Run on background thread")
}

あるいは、2行のコードで何かしたい場合は、

DispatchQueue.global(qos: .background).async {
    print("Run on background thread")

    DispatchQueue.main.async {
        print("We finished that.")
        // only back on the main thread, may you access UI:
        label.text = "Done."
    }
}

Swift 3のGDCに関する詳細な情報は このチュートリアル にもあります。

40
Said Sikira

Jameson Quaveの tutorial から

スイフト2

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    //All stuff here
})
34
alex

バックグラウンドで実行したい変更と、UIで実行したい更新とを区別する必要があります。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    // do your task

    dispatch_async(dispatch_get_main_queue()) {
        // update some UI
    }
}
22
phuongle

Swift 4.x

これをファイルに入れてください。

func background(work: @escaping () -> ()) {
    DispatchQueue.global(qos: .userInitiated).async {
        work()
    }
}

func main(work: @escaping () -> ()) {
    DispatchQueue.main.async {
        work()
    }
}

それからあなたが必要とするところでそれを呼んでください:

background {
     //background job
     main {
       //update UI (or what you need to do in main thread)
     }
}
19

Swift 4.2とXcode 10.1では

3種類のキューがあります。

1. Main Queue:メインキューは、システムによって作成され、アプリケーションのメインスレッドに関連付けられたシリアルキューです。

2. Global Queue:グローバルキューはタスクの優先順位に関して要求できる並行キューです。

3.カスタムキュー:はユーザーが作成できます。カスタムコンカレントキューは、Quality of Serviceプロパティ(QoS)を指定することによって、常にグローバルキューの1つにマッピングされます。

DispatchQueue.main//Main thread
DispatchQueue.global(qos: .userInitiated)// High Priority
DispatchQueue.global(qos: .userInteractive)//High Priority (Little Higher than userInitiated)
DispatchQueue.global(qos: .background)//Lowest Priority
DispatchQueue.global(qos: .default)//Normal Priority (after High but before Low)
DispatchQueue.global(qos: .utility)//Low Priority
DispatchQueue.global(qos: .unspecified)//Absence of Quality

これらすべてのキューは2つの方法で実行できます。

1.同期実行

2.非同期実行

DispatchQueue.global(qos: .background).async {
    // do your job here
    DispatchQueue.main.async {
        // update ui here
    }
}

//Perform some task and update UI immediately.
DispatchQueue.global(qos: .userInitiated).async {  
    // Perform task
    DispatchQueue.main.async {  
        // Update UI
        self.tableView.reloadData()  
    }
}

//To call or execute function after some time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    //Here call your function
}

//If you want to do changes in UI use this
DispatchQueue.main.async(execute: {
    //Update UI
    self.tableView.reloadData()
})

AppCodaから: https://www.appcoda.com/grand-central-dispatch/ /

//This will print synchronously means, it will print 1-9 & 100-109
func simpleQueues() {
    let queue = DispatchQueue(label: "com.appcoda.myqueue")

    queue.sync {
        for i in 0..<10 {
            print("????", i)
        }
    }

    for i in 100..<110 {
        print("Ⓜ️", i)
    }
}

//This will print asynchronously 
func simpleQueues() {
    let queue = DispatchQueue(label: "com.appcoda.myqueue")

    queue.async {
        for i in 0..<10 {
            print("????", i)
        }
    }

    for i in 100..<110 {
        print("Ⓜ️", i)
    }
}
18
iOS

それでも、良い答えは、とにかく私のオブジェクト指向ソリューションSwift 5では最新を共有したいことです。

チェックしてください: AsyncTask

概念的にはAndroidのAsyncTaskに触発されて、私はSwiftで私自身のクラスを書いた

AsyncTaskを使用すると、UIスレッドを正しく簡単に使用できます。このクラスを使用すると、バックグラウンド操作を実行して結果をUIスレッドに公開できます。

ここにいくつかの使用例があります

例1 -

AsyncTask(backgroundTask: {(p:String)->Void in//set BGParam to String and BGResult to Void
        print(p);//print the value in background thread
    }).execute("Hello async");//execute with value 'Hello async'

例2 -

let task2=AsyncTask(beforeTask: {
           print("pre execution");//print 'pre execution' before backgroundTask
        },backgroundTask:{(p:Int)->String in//set BGParam to Int & BGResult to String
            if p>0{//check if execution value is bigger than zero
               return "positive"//pass String "poitive" to afterTask
            }
            return "negative";//otherwise pass String "negative"
        }, afterTask: {(p:String) in
            print(p);//print background task result
    });
    task2.execute(1);//execute with value 1

2つのジェネリック型があります。

  • BGParam - 実行時にタスクに送信されるパラメータの型.
  • BGResult - バックグラウンド計算の結果の型.

    AsyncTaskを作成するときには、バックグラウンドタスクの受け渡しに必要なものは何でも使用できますが、これらの種類が必要ない場合は、単にVoidname__に設定するか、短い構文を使用して未使用としてマークできます。 :()

非同期タスクが実行されると、3つのステップを経ます。

  1. beforeTask:()->Voidはタスクが実行される直前にUIスレッドで呼び出されます。
  2. 直後にバックグラウンドスレッドで呼び出されたbackgroundTask: (param:BGParam)->BGResult
  3. バックグラウンドタスクの結果としてUIスレッド上で呼び出されたafterTask:(param:BGResult)->Void
9
Nikita Kurtin

OPの質問はすでに上記のように回答されているので、速度に関する考慮事項をいくつか追加します。

特にタスクが低電力コアに割り当てられていると思われるiPhone Xで、 .background スレッド優先順位でタスクを実行することはお勧めしません。

これは、XMLファイルから(バッファリングを使用して)読み取り、データ補間を実行する、計算量の多い関数からの実際のデータです。

デバイス名/ .background / .utility / .default / .userInitiated / .userInteractive

  1. iPhone X:18.7秒/ 6.3秒/ 1.8秒/ 1.8秒/ 1.8秒
  2. iPhone 7:4.6秒/ 3.1秒/ 3.0秒/ 2.8秒/ 2.6秒
  3. iPhone 5秒:7.3秒/ 6.1秒/ 4.0秒/ 4.0秒/ 3.8秒

データセットはすべてのデバイスで同じというわけではありません。これはiPhone Xで最大、iPhone 5では最小です。

6
Cosmin

Grand Central Dispatchは、当社のiOSアプリでマルチタスクを処理するために使用されます。

あなたはこのコードを使うことができます

// Using time interval

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1) {
    print("Hello World")
}

// Background thread
queue.sync {
     for i in 0..<10 {
          print("Hello", i)
     }
}

// Main thread
for i in 20..<30 {
     print("Hello", i)
}

より多くの情報はこのリンクを使用します: https://www.programminghub.us/2018/07/integrate-dispatcher-in-Swift.html

1
Anil Dhameliya

私は本当にDan Beaulieuの答えが好きですが、それはSwift 2.2では動作しません、そして私たちはそれらの厄介な強制的な展開を避けることができると思います!

func backgroundThread(delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) {

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {

        background?()

        if let completion = completion{
            let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
            dispatch_after(popTime, dispatch_get_main_queue()) {
                completion()
            }
        }
    }
}
1
rougeExciter

スレッドの多目的機能

public enum QueueType {
        case Main
        case Background
        case LowPriority
        case HighPriority

        var queue: DispatchQueue {
            switch self {
            case .Main:
                return DispatchQueue.main
            case .Background:
                return DispatchQueue(label: "com.app.queue",
                                     qos: .background,
                                     target: nil)
            case .LowPriority:
                return DispatchQueue.global(qos: .userInitiated)
            case .HighPriority:
                return DispatchQueue.global(qos: .userInitiated)
            }
        }
    }

    func performOn(_ queueType: QueueType, closure: @escaping () -> Void) {
        queueType.queue.async(execute: closure)
    }

それを使用してください:

performOn(.Background) {
    //Code
}
0
Viral Savaliya
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
    // Conversion into base64 string
    self.uploadImageString =  uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})
0
A.G