신속한 배경 스레드를 사용하는 방법은 무엇입니까?


329

스레딩을 신속하게 사용하는 방법은 무엇입니까?

dispatchOnMainThread:^{

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

}];

어느 부분이 변환에 문제가 있습니까?
nschum

2
]마지막 줄에서 세미콜론 앞에 왜 있습니까?
akashivskyy 2016 년

3
어디에 붙어 있거나 도움이 필요한지를 설명하면 도움이 될 것입니다.
nsuinteger

4
실제로 도움이된다면 정답을 수락해야하며 다른 사람도 올바른 해결책을 찾는 데 도움이됩니다.
Amit Singh

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

답변:


708

스위프트 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")
    }
}

스위프트 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).

자세한 내용은 Apple 설명서를 참조하십시오.


23
그리고 누군가가 Swift와 같은 구문을 원한다면, 구문에 설탕을 추가하는 Async 를 만들었습니다Async.background {}
tobiasdm

xCode 6.0.1 및 ios 8에서 코드를 사용하고 있습니다. "QOS_CLASS_BACKGROUND"반환 클래스로 오류가 발생하고 UInt32 유형이며 "dispatch_get_global_queue"는 int로 첫 번째 매개 변수가 필요하므로 유형 오류가 발생합니다.
Zalak Patel

따라서 Xcode 6.1.1에서는 단순한 단순 "QOS_CLASS_BACKGROUND"를 사용하는 데 오류가 발생하지 않습니다. 고정되어 있습니까?
Lucas Goossen

@LucasGoossen 예, 수정되었습니다. 그에 따라 게시물을 업데이트했습니다.
tobiasdm

1
@NikitaPronchik 대답이 명확하지 않습니까? 그렇지 않으면 자유롭게 편집하십시오.
tobiasdm 2016 년

123

가장 좋은 방법은 여러 번 액세스 할 수있는 재사용 가능한 기능을 정의하는 것입니다.

재사용 가능한 기능 :

예를 들어 전역 함수로서 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?()
        }
    }
}

참고 : 스위프트 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
    })

1
좋은 발췌 문장, 정답이어야합니다. @ 데일 클리포드
6

저수준 C 라이브러리에서 오래된 GCD 방법에 액세스하기위한 뛰어난 수준의 최신 Swift-y 접근 방식. Swift에서 표준으로 제공되어야합니다.
Craig Grummitt

2
아주 좋아요 지연이 완료 블록에 대해서만 작동하는지 확인 하시겠습니까? 따라서 A.의 지연은 영향을 미치지 않으며 백그라운드 블록은 지연없이 즉시 실행됩니다.
ObjectiveTC

1
다음을 교체 할 수 있어야한다 if(background != nil){ background!(); }background?()다소 swiftier 구문?
Simon Bengtsson

1
Swift 3에 대해 이것을 업데이트 하시겠습니까? 자동 변환기가로 전환 DispatchQueue.global(priority: Int(DispatchQoS.QoSClass.userInitiated.rawValue)).async {했지만과 같은 오류가 발생 cannot invoke initializer for type 'Int' with an argument list of type '(qos_class_t)'합니다. 작동하는 솔루션은 여기 ( DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async) 에서 찾을 수 있습니다 .
Dev-iL

111

swift5의 Dan Beaulieu의 답변 (swift 3.0.1부터 작동).

스위프트 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
})

Swift 3.0.1 형식으로 업데이트 해 주셔서 감사합니다.
데일 클리포드

1
나는 살아있는 사람보다 더 많은 확장을 사용합니다. 그러나 원래 확장과 전혀 다른 확장을 사용하면 실제로 위험이 있습니다!
Fattie

@Frouo 매우 우아합니다. 4 개의 비동기 호출이 모두 완료 될 때 완료 처리기를 추가 할 수 있습니까? 나는 그 주제에서 약간 벗어난 것을 알고 있습니다.
eonist

1
p 그 링크를 잊어 버려. 디스패치 그룹 만 있으면됩니다. 매우 간단합니다. 전혀 걱정하지 마십시오!
Fattie

1
@DilipJangid는 background클로저 작업이 매우 길지 않으면 (~ = 무한한 경우) 할 수 없습니다 . 이 방법은 백그라운드 작업을 실행해야하는 시간 인 유한 한 시간 동안 지속됩니다. 따라서 completion백그라운드 작업 실행 시간 + 지연이 경과하자마자 폐쇄가 호출됩니다.
frouo

42

스위프트 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."
    }
}

이 튜토리얼 에서 Swift 3의 GDC에 대한 자세한 정보를 얻을 수 있습니다 .


말했다. 귀하의 답변이 최고이므로, "완료되면 다시 전화하는 방법"을 보여주는 일련의 코드를 던졌습니다. 편안하게 긴장을 풀거나 편집하십시오, 건배
Fattie

35

에서 제임슨 Quave의 튜토리얼

스위프트 2

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

3
명확히하기 위해, 왜 대답 대신에 이것이 사용됩니까? 이것은 단지 오래된 API입니까?
사이렌

1
@Sirens 저는 이것이 iOS 8을 지원하는 앱에 매우 유용 할 것이라고 생각합니다.
bperdue

프로세스를 강제 실행하기 위해 iOs 8.2에 이것을 사용합니다.
μολὼν.λαβέ

DISPATCH_QUEUE_PRIORITY_DEFAULT는 QOS_CLASS_DEFAULT로 되돌아갑니다. 그래서 더 높은 수준의 / 허용되는 구문이라고 말할 수 있습니다.
PostCodeism

34

Swift 4.2 및 Xcode 10.1에서

대기열에는 세 가지 유형이 있습니다.

1. 메인 큐 : 메인 큐는 시스템에 의해 생성되고 응용 프로그램 메인 스레드와 연결된 직렬 큐입니다.

2. Global Queue : Global Queue는 작업 우선 순위와 관련하여 요청할 수있는 동시 대기열입니다.

3. 사용자 지정 대기열 : 사용자 가 만들 수 있습니다. 사용자 정의 동시 큐는 항상 QoS (Quality of Service) 특성을 지정하여 글로벌 큐 중 하나에 맵핑됩니다.

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


나는 당신이 .background QoS 를 사용할 때 어떤 변화도 보지 못했지만 .userInitiated나에게 잘 맞았습니다..background
rust

24

스위프트 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)
     }
}

22

UI에서 실행하려는 업데이트와 백그라운드에서 실행하려는 변경 사항을 분리해야합니다.

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

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

그래서 dispatch_async(dispatch_get_main_queue()) { // update some UI }배경 문 (외부 블록)을 실행 할 때 호출되는?
justColbs

Swift 2.3 이하에만 해당되지 않습니까?
Surz

9

그래도 좋은 답변이지만 어쨌든 객체 지향 솔루션 을 신속하게 공유하고 싶습니다 5 .

그것을 확인하십시오 : AsyncTask

안드로이드의 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

두 가지 일반 유형이 있습니다.

  • BGParam -실행시 태스크로 전송되는 매개 변수의 유형입니다.
  • BGResult -백그라운드 계산 결과의 유형.

    AsyncTask를 만들 때 백그라운드 작업을 전달 및 종료 해야하는 모든 유형으로 해당 유형을 수행 할 수 있지만 해당 유형이 필요하지 않은 경우 다음 유형으로 설정 Void하거나 더 짧은 구문 으로 사용하지 않는 것으로 표시 할 수 있습니다 .()

비동기 작업이 실행되면 3 단계를 거칩니다.

  1. beforeTask:()->Void 작업이 실행되기 직전에 UI 스레드에서 호출됩니다.
  2. backgroundTask: (param:BGParam)->BGResult 직후 백그라운드 스레드에서 호출
  3. afterTask:(param:BGResult)->Void 백그라운드 작업의 결과로 UI 스레드에서 호출

4
이것은 나를 위해 훌륭하게 작동합니다. 잘 했어, github에 올려 놓지 않겠습니까?
36 디자인으로

8

OP 질문에 이미 답변되었으므로 속도 고려 사항을 추가하고 싶습니다.

저전력 코어에 작업이 할당 된 것처럼 보이는 iPhone X에서 .background thread 우선 순위로 작업을 실행하지 않는 것이 좋습니다 .

다음은 XML 파일에서 버퍼링을 읽고 데이터 보간을 수행하는 계산 집약적 인 함수의 실제 데이터입니다.

장치 이름 / .background / .utility / .default / .userInitiated / .userInteractive

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

데이터 세트가 모든 장치에 대해 동일하지는 않습니다. iPhone X에서 가장 크고 iPhone 5에서 가장 작습니다.


4

스위프트 5

쉽게 만들려면 다음 내용으로 "DispatchQueue + Extensions.swift"파일을 만드십시오.

import Foundation

typealias Dispatch = DispatchQueue

extension Dispatch {

    static func background(_ task: @escaping () -> ()) {
        Dispatch.global(qos: .background).async {
            task()
        }
    }

    static func main(_ task: @escaping () -> ()) {
        Dispatch.main.async {
            task()
        }
    }
}

사용법 :

Dispatch.background {
    // do stuff

    Dispatch.main { 
        // update UI
    }
}

2

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


2

나 사용 다목적 기능

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
}

1

나는 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()
            }
        }
    }
}

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

-3

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);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.