Swift 3, Swift 4 이상에서 dispatch_sync, dispatch_async, dispatch_after 등을 어떻게합니까?


243

Swift 2.x (또는 1.x) 프로젝트에는 다음과 같은 코드가 많이 있습니다.

// Move to a background thread to do some long running work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    dispatch_async(dispatch_get_main_queue()) {
        self.imageView.image = image
    }
}

또는 다음과 같은 것들이 실행을 지연시킵니다.

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
    print("test")
}

또는 Grand Central Dispatch API의 다른 모든 용도 중 하나 ...

Swift 3 용 Xcode 8 (베타)에서 프로젝트를 열었으므로 모든 종류의 오류가 발생합니다. 그들 중 일부는 내 코드를 수정하도록 제안하지만 모든 수정 사항이 작동 코드를 생성하는 것은 아닙니다. 이것에 대해 어떻게해야합니까?


여기에
대답

답변:


343

Swift는 처음부터 ObjC 및 C를 더욱 신속하게 만드는 기능을 제공하여 각 버전에 더 많은 기능을 추가했습니다. 이제 Swift 3에서 새로운 "멤버로 가져 오기" 기능을 사용하면 특정 스타일의 C API (클래스처럼 작동하는 데이터 유형과 함께 사용할 수있는 전역 함수)가있는 프레임 워크를 사용할 수 있습니다. 스위프트 네이티브 API와 비슷하게 작동합니다. 데이터 유형은 Swift 클래스로 가져오고 관련 전역 함수는 해당 클래스의 메소드 및 특성으로 가져 오며 상수 세트와 같은 일부 관련 항목은 적절한 경우 하위 유형이 될 수 있습니다.

Xcode 8 / Swift 3 베타에서 Apple은 Dispatch 프레임 워크를 훨씬 더 Swifty로 만들기 위해이 기능을 (다른 몇 가지와 함께) 적용했습니다. (그리고 Core Graphics 도 마찬가지입니다.) Swift 오픈 소스 노력을 겪고 있다면 이것은 뉴스 가 아니지만 Xcode의 첫 번째 사례 입니다.

프로젝트를 Swift 3으로 옮기는 첫 번째 단계 는 Xcode 8에서 프로젝트를 열고 메뉴에서 편집> 변환> 현재 Swift 구문으로 ... 를 선택하는 것입니다. 이름이 바뀐 모든 API 및 기타 변경 사항에 필요한 모든 변경 사항이 검토 및 승인과 함께 한 번에 적용됩니다. (종종 한 줄의 코드가 한 번에 이러한 변경 중 둘 이상에 영향을 받으므로 오류 수정에 개별적으로 응답하면 모든 것이 올바르게 처리되지 않을 수 있습니다.)

결과적으로 작업을 배경으로 되 돌리는 일반적인 패턴은 다음과 같습니다.

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    DispatchQueue.main.async {
        self.imageView.image = image
    }
}

.userInitiated이전 DISPATCH_QUEUE_PRIORITY상수 중 하나 대신 사용 하고 있습니다. 서비스 품질 (QoS) 지정자는 OS X 10.10 / iOS 8.0에 도입되어 시스템이 작업의 우선 순위를 지정하고 이전 우선 순위 지정자를 더 이상 사용하지 않는 명확한 방법을 제공합니다. 자세한 내용 은 백그라운드 작업 및 에너지 효율성 에 관한 Apple의 문서 를 참조하십시오.

당신이 작업을 구성하기 위해 자신의 대기열을 유지하는 경우 (통지 그런데, 방법은 하나가 지금과 같은 얻을 수 DispatchQueueAttributes입니다 OptionSet당신이 옵션을 결합 컬렉션 스타일의 리터럴을 사용할 수 있도록)

class Foo { 
    let queue = DispatchQueue(label: "com.example.my-serial-queue",
                           attributes: [.serial, .qosUtility])
    func doStuff() {
        queue.async {
            print("Hello World")
        }
    }
}

dispatch_after나중에 일하는 데 사용 하십니까? 그것은 대기열에있는 방법이기도하며 DispatchTime, 다양한 숫자 유형에 대한 연산자가 있으므로 전체 또는 분수 초를 추가 할 수 있습니다.

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // in half a second...
    print("Are we there yet?")
}

Xcode 8에서 인터페이스를 열어서 새로운 Dispatch API를 둘러 볼 수 있습니다 .Open을 사용하여 Dispatch 모듈을 찾거나 DispatchQueueSwift 프로젝트 / 놀이터에 기호 (예 :)를 입력하고 명령을 클릭 한 다음 주변을 둘러보세요 거기에서 모듈. ( Apple의 새롭고 새로운 API 참조 웹 사이트 및 Xcode 문서 뷰어에서 Swift Dispatch API를 찾을 수 있지만 C 버전의 문서 내용이 아직 옮겨지지 않은 것 같습니다.)

자세한 내용은 마이그레이션 안내서 를 참조하십시오 .


3
Xcode 8 Beta 6의 경우 .serial 속성이 사라지고 기본 동작 -forums.developer.apple.com/message/159457#159457
hyouuu

6
XCode 8.1 이후 업데이트가 필요합니다. 속성 레이블이 사라졌고 대신 'DispatchQueue.global (qos : .background) .async'를 사용할 수 있습니다
Mike M

2
훌륭한 답변입니다. 정말 내 머리를 구하는 데 도움이되었습니다.
Mohsin Khubaib Ahmed

나는 qos:대신에 사용해야 했다attributes:
이슬람 Q.

myQueue.async {class Foo예가 아니어야합니까 ?
vacawama 2016 년

142

Xcode 8 베타 4에서는 작동하지 않습니다 ...

사용하다:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    print("Are we there yet?")
}

비동기 두 가지 방법으로 :

DispatchQueue.main.async {
    print("Async1")
}

DispatchQueue.main.async( execute: {
    print("Async2")
})

UI를 차단하지 않습니까?
user25

72

이것은 다음에 Swift 4대한 좋은 예입니다 async.

DispatchQueue.global(qos: .background).async {
    // Background Thread
    DispatchQueue.main.async {
        // Run UI Updates or call completion block
    }
}

hi DispatchQueue.main.async {// 백그라운드 업데이트 이전에 UI 업데이트 실행}이 실행되고 있습니다
Uma Achanta

Kotlin의 코 루틴과 유사
user25

40

Xcode 8에서 사용 :

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

26

스위프트 5.2, 4 이상

메인 및 백그라운드 큐

let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread") 

비동기 및 동기화 스레드 작업 !

 background.async { //async tasks here } 
 background.sync { //sync tasks here } 

비동기 스레드는 기본 스레드와 함께 작동합니다.

동기화 스레드는 실행 중에 메인 스레드를 차단합니다.


1
메인 스레드 (UI)를 차단하지 않고 어떻게 동기화 스레드를 사용합니까 ?? 백그라운드에서 일련의 일을 실행하고 싶지만 이러한 일들은 동기화 방식으로 하나씩 실행되어야합니다. 이 시간 동안 UI는 반응을 유지해야합니다. 어떻게 하시겠습니까?
iKK

NSOperationQueue를 사용하십시오. NSOperation을 나타내는 각 작업 참조 stackoverflow.com/a/19746890/5215474
Saranjith

12

Swift 4.1과 5. 우리는 코드의 여러 곳에서 대기열을 사용합니다. 그래서 모든 대기열이있는 Threads 클래스를 만들었습니다. Threads 클래스를 사용하지 않으려는 경우 클래스 메소드에서 원하는 큐 코드를 복사 할 수 있습니다.

class Threads {

  static let concurrentQueue = DispatchQueue(label: "AppNameConcurrentQueue", attributes: .concurrent)
  static let serialQueue = DispatchQueue(label: "AppNameSerialQueue")

  // Main Queue
  class func performTaskInMainQueue(task: @escaping ()->()) {
    DispatchQueue.main.async {
      task()
    }
  }

  // Background Queue
  class func performTaskInBackground(task:@escaping () throws -> ()) {
    DispatchQueue.global(qos: .background).async {
      do {
        try task()
      } catch let error as NSError {
        print("error in background thread:\(error.localizedDescription)")
      }
    }
  }

  // Concurrent Queue
  class func perfromTaskInConcurrentQueue(task:@escaping () throws -> ()) {
    concurrentQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Concurrent Queue:\(error.localizedDescription)")
      }
    }
  }

  // Serial Queue
  class func perfromTaskInSerialQueue(task:@escaping () throws -> ()) {
    serialQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Serial Queue:\(error.localizedDescription)")
      }
    }
  }

  // Perform task afterDelay
  class func performTaskAfterDealy(_ timeInteval: TimeInterval, _ task:@escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: (.now() + timeInteval)) {
      task()
    }
  }
}

기본 대기열 사용을 보여주는 예.

override func viewDidLoad() {
    super.viewDidLoad()
     Threads.performTaskInMainQueue {
        //Update UI
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.