Как использовать фоновый поток в swift?

Как использовать потоки в swift?

dispatchOnMainThread:^{

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

}];

Ответ 1

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

Для получения дополнительной информации см. Документация яблок

Ответ 2

Рекомендуется определить функцию многократного использования, к которой можно обращаться несколько раз.

ВОЗМОЖНАЯ ФУНКЦИЯ:

например, где-то вроде 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
    })

Б. Чтобы запустить процесс в фоновом режиме, затем выполнить завершение на переднем плане:

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

Ответ 3

Дэн Болье отвечает в swift5 (также работает с 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
})

Ответ 4

версия Swift 3

Swift 3 использует новый класс DispatchQueue для управления очередями и потоками. Чтобы запустить что-то в фоновом потоке, вы должны использовать:

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

Или если вы хотите что-то в двух строках кода:

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."
    }
}

Вы также можете получить подробную информацию о GDC в Swift 3 в этом учебнике.

Ответ 5

Из учебник Jameson Quave

Swift 2

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

Ответ 6

Вам нужно отделить изменения, которые вы хотите запустить в фоновом режиме, из обновлений, которые вы хотите запустить в пользовательском интерфейсе:

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

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

Ответ 7

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

Ответ 8

В Swift 4.2 и Xcode 10.1

У нас есть три типа очередей:

1. Основная очередь. Главная очередь - это последовательная очередь, которая создается системой и связана с основным потоком приложения.

2. Глобальная очередь. Глобальная очередь - это параллельная очередь, которую мы можем запросить относительно приоритета задач.

3. Пользовательские очереди: могут быть созданы пользователем. Настраиваемые параллельные очереди всегда отображаются в одну из глобальных очередей путем указания свойства Quality of Service (QoS).

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

Все эти очереди могут быть выполнены двумя способами

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

Ответ 9

Хорошие ответы, хотя, в любом случае я хочу поделиться своим объектно - ориентированным решением до даты быстрых 5.

пожалуйста, проверьте это: AsyncTask

Концептуально вдохновленный Android AsyncTask, я написал свой собственный класс в Swift

AsyncTask позволяет правильно и легко использовать поток пользовательского интерфейса. Этот класс позволяет выполнять фоновые операции и публиковать результаты в потоке пользовательского интерфейса.

Вот несколько примеров использования

Пример 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, вы можете добавить эти типы к тому, что вам нужно передать в фоновую задачу и из нее, но если вам не нужны эти типы, вы можете пометить его как неиспользуемый, просто установив его: Void или с более коротким синтаксисом.: ()

Когда асинхронная задача выполняется, она проходит 3 этапа:

  1. beforeTask:()->Void вызывается в потоке пользовательского интерфейса непосредственно перед выполнением задачи.
  2. backgroundTask: (param:BGParam)->BGResult вызывается в фоновом потоке сразу после
  3. afterTask:(param:BGResult)->Void вызывается в потоке пользовательского интерфейса с результатом фоновой задачи

Ответ 10

Поскольку вопрос OP уже был выше, я просто хочу добавить некоторые соображения скорости:

Я не рекомендую запускать задачи с приоритетом.background thread, особенно на iPhone X, где задача, по-видимому, выделяется на ядрах с малой мощностью.

Вот некоторые реальные данные из вычислительно интенсивной функции, которая читает из файла XML (с буферизацией) и выполняет интерполяцию данных:

Имя устройства /.background/.utility/.default/.userInitiated/.userInteractive

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

Обратите внимание, что набор данных не одинаковый для всех устройств. Это самый большой на iPhone X и самый маленький на iPhone 5s.

Ответ 11

Мне очень нравится ответ Дэн Боулье, но он не работает с 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()
            }
        }
    }
}

Ответ 12

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

Ответ 13

dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
    // Conversion into base64 string
    self.uploadImageString =  uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})

Ответ 14

Многоцелевая функция для потока

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
}

Ответ 15

в Swift 4.2 это работает.

import Foundation

class myThread: Thread
{
    override func main() {
        while(true) {
            print("Running in the Thread");
            Thread.sleep(forTimeInterval: 4);
        }
    }
}

let t = myThread();
t.start();

while(true) {
    print("Main Loop");
    sleep(5);
}