답변:
UI 스레드에서 호출 된 경우 프로그램을 잠그는 절전 모드 대신 NSTimer
디스패치 타이머 사용을 고려하십시오 .
그러나 현재 스레드에서 지연이 정말로 필요한 경우 :
do {
sleep(4)
}
이것은 sleep
UNIX 의 기능을 사용합니다 .
dispatch_after
대부분의 경우 sleep(time)
절전을 수행하는 스레드가 다른 작업을 수행하지 못하도록 차단하는 것보다 블록을 사용하는 것이 좋습니다 . dispatch_after
작업중 인 스레드를 사용할 때 차단되지 않으므로 그 동안 다른 작업을 수행 할 수 있습니다.
응용 프로그램의 주요 스레드에서 작업하는 경우 sleep(time)
해당 시간 동안 UI가 응답하지 않기 때문에 앱의 사용자 경험에 좋지 않습니다.
스레드 후 중단하는 대신 코드 블록 실행을 예약 한 후 전달 :
let seconds = 4.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
// Put your code which should be executed with a delay here
}
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
}
.now() + .seconds(4)
: 오류가 있습니다expression type is ambiguous without more context
.now() + .seconds(5)
할 필요가 없습니다.now() + 5
swift 3.0의 다양한 접근 방식 비교
1. 수면
이 메소드에는 콜백이 없습니다. 이 줄 바로 뒤에 코드를 넣어 4 초 안에 실행하십시오. 시간이 지날 때까지 테스트 버튼과 같은 UI 요소를 사용하여 사용자가 반복하지 못하게합니다. 수면이 시작될 때 버튼이 정지 된 상태이지만 활동 표시기와 같은 다른 요소는 여전히 정지없이 회전합니다. 수면 중에는이 동작을 다시 트리거 할 수 없습니다.
sleep(4)
print("done")//Do stuff here
2. 파견, 수행 및 타이머
이 세 가지 방법은 비슷하게 작동하며 모두 다른 구문과 약간 다른 기능으로 콜백을 통해 백그라운드 스레드에서 실행됩니다.
디스패치는 일반적으로 백그라운드 스레드에서 무언가를 실행하는 데 사용됩니다. 함수 호출의 일부로 콜백이 있습니다.
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
print("done")
})
실제로는 간단한 타이머입니다. 지연으로 타이머를 설정 한 다음 선택기로 기능을 트리거합니다.
perform(#selector(callback), with: nil, afterDelay: 4.0)
func callback() {
print("done")
}}
마지막으로 타이머는 콜백을 반복하는 기능도 제공하므로이 경우에는 유용하지 않습니다.
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false)
func callback() {
print("done")
}}
이 세 가지 방법 모두에서 버튼을 클릭하여 트리거하면 UI가 멈추지 않으며 다시 클릭 할 수 있습니다. 버튼을 다시 클릭하면 다른 타이머가 설정되고 콜백이 두 번 트리거됩니다.
결론적으로
네 가지 방법 중 어느 것도 그 자체로는 충분히 효과가 없습니다. sleep
사용자 상호 작용을 비활성화하므로 화면이 " 정지 (실제로는 아님)"하고 사용자 경험이 좋지 않습니다. 다른 세 가지 방법은 화면을 정지시키지 않지만 여러 번 트리거 할 수 있으며 대부분의 경우 사용자가 다시 전화를 걸기 전에 전화를받을 때까지 기다립니다.
따라서 더 나은 디자인은 화면 차단과 함께 세 가지 비동기 방법 중 하나를 사용하는 것입니다. 사용자가 버튼을 클릭하면 상단에 회전 활동 표시기가있는 반투명보기로 전체 화면을 덮어 버튼 클릭이 처리되고 있음을 사용자에게 알립니다. 그런 다음 콜백 기능에서보기 및 표시기를 제거하여 사용자에게 조치가 올바르게 처리되었음을 알리십시오.
@objc
에서 perform(...)
옵션에 대한 콜백 함수 앞에 추가해야합니다 . 그래서처럼@objc func callback() {
내가 사용하는 것을의 Palle 동의 dispatch_after
입니다 좋은 선택이 여기에. 그들은 꽤 있습니다하지만 당신은 아마 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
}
DispatchTime
Swift 2에서는 사용할 수 없었던 유형 변환이 필요했습니다 let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
.
Swift 4.2 및 Xcode 10.1에서
총 4 가지 방법이 있습니다. 이 옵션 중 1 은 일정 시간 후에 함수를 호출하거나 실행하는 것이 좋습니다. 수면 () 사용 적어도 경우이다.
옵션 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)
무언가를 실행하기 위해 일정 시간 후에 함수를 호출하려면 sleep을 사용하지 마십시오 .
@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_time
(같이 의 Palle의 대답 ) 다른 유효한 옵션입니다. 그러나 취소 하기는 어렵습니다 . 을 사용 NSTimer
하여 지연된 이벤트가 발생하기 전에 취소하려면 전화 만하면됩니다.
timer.invalidate()
sleep
스레드에서 수행되는 모든 작업을 중지하므로 특히 주 스레드에서 사용 하지 않는 것이 좋습니다.
지연 기능을 쉽게 사용할 수 있도록 확장 기능을 만들 수 있습니다 (구문 : 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
})
코드가 이미 백그라운드 스레드에서 실행중인 경우 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)
}
(코드가 메인 스레드에서 실행될 때 제안에 대한 다른 답변을 참조하십시오.)
간단한 시간 지연을 만들려면 Darwin을 가져온 다음 sleep (seconds)을 사용하여 지연을 수행 할 수 있습니다. 단 몇 초 밖에 걸리지 않으므로보다 정확한 측정을 위해서는 Darwin을 가져 와서 매우 정확한 측정을 위해 usleep (백만 분의 1 초)을 사용할 수 있습니다. 이것을 테스트하기 위해 다음과 같이 썼습니다.
import Darwin
print("This is one.")
sleep(1)
print("This is two.")
usleep(400000)
print("This is three.")
인쇄 후 1 초 동안 기다렸다가 인쇄 한 다음 0.4 초 동안 기다렸다가 인쇄합니다. 모두 예상대로 작동했습니다.
이것은 가장 간단합니다
delay(0.3, closure: {
// put her any code you want to fire it with delay
button.removeFromSuperview()
})