programing

Swift에서 지연을 발생시키는 방법은 무엇입니까?

cafebook 2023. 4. 13. 21:09
반응형

Swift에서 지연을 발생시키는 방법은 무엇입니까?

특정 시점에서 앱을 일시 정지하고 싶다.즉, 앱이 코드를 실행해 주었으면 하는 것입니다만, 어느 시점에서 4초간 일시 정지하고 나서, 나머지 코드를 계속 실행해 주세요.이거 어떻게 해?

Swift를 사용하고 있습니다.

「」의 dispatch_after.sleep(time)수면이 이루어지는 실이 다른 작업을 하는 것을 차단하기 때문입니다.사용할 때dispatch_after작업하는 스레드는 차단되지 않기 때문에 그 사이에 다른 작업을 수행할 수 있습니다.
프로그램의 스레드에서 를 합니다.sleep(time)이 시간 동안 UI가 응답하지 않으므로 앱 사용자 환경에 좋지 않습니다.

한 후 디스패치:

Swift 3 3.0

let seconds = 4.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
    // Put your code which should be executed with a delay here
}

비동기 컨텍스트에서의 Swift 5 5.5:

func foo() async {
    try await Task.sleep(nanoseconds: UInt64(seconds * Double(NSEC_PER_SEC)))
    // Put your code which should be executed with a delay here
}

Swift < 3.0

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
}

스레드에서 UI를 사용하는 것이 .NSTimer는는디또

그러나 현재 스레드에서 지연이 필요한 경우:

do {
    sleep(4)
}

UNIX 의 기능을 사용합니다.

swift 3.0의 다양한 접근법 비교

1. 수면

이 메서드에는 콜백이 없습니다.이 행 바로 뒤에 코드를 삽입하여 4초 후에 실행합니다.시간이 지날 때까지 사용자가 테스트 버튼과 같은 UI 요소를 반복하지 않도록 합니다.수면이 시작되면 버튼이 정지되어 있지만, 활동 지표와 같은 다른 요소들은 정지되지 않고 여전히 회전하고 있습니다.절전 모드 중에는 이 작업을 다시 트리거할 수 없습니다.

sleep(4)
print("done")//Do stuff here

여기에 이미지 설명 입력

2. 디스패치, 퍼포먼스 및 타이머

이들 3가지 방식은 동일하게 동작합니다.모두 다른 구문과 약간 다른 기능을 가진 콜백이 있는 백그라운드스레드 상에서 실행됩니다.

디스패치는 일반적으로 백그라운드 스레드에서 무언가를 실행하기 위해 사용됩니다.함수 호출의 일부로 콜백이 있습니다.

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
    print("done")
})

Perform은 실제로는 단순한 타이머입니다.지연이 있는 타이머를 설정한 다음 셀렉터에 의해 기능을 트리거합니다.

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는 사용자의 조작을 무효로 하기 때문에, 화면이 「실제로 표시되지 않는다」(실제로 표시되지 않는다)가 되어, 유저 익스피리언스가 나빠집니다.다른 3가지 방법에서는 화면이 정지되지는 않지만 여러 번 트리거할 수 있습니다.대부분의 경우 콜이 반환될 때까지 기다렸다가 사용자가 콜을 다시 발신할 수 있도록 해야 합니다.

따라서 화면 차단 기능이 있는 3가지 비동기 방식 중 하나를 사용하는 것이 좋습니다.사용자가 버튼을 클릭할 때 화면 전체를 회전하는 액티비티 인디케이터와 함께 반투명 보기로 가리면 버튼 클릭이 처리되고 있음을 사용자에게 알립니다.그런 다음 콜백 함수의 뷰와 인디케이터를 삭제하고 액션이 적절하게 처리되었음을 사용자에게 알립니다.

Swift 4.2 및 Xcode 10.1의 경우

지연에는 총 4가지 방법이 있습니다.이들 옵션 중 1은 일정 시간 후에 함수를 호출하거나 실행하는 것이 좋습니다.sleep()은 최소 사용 사례입니다.

옵션 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을 사용하지 마세요.

합니다.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
}

보다 편리한 기능을 갖춘 프레임워크를 원하신다면 HandySwift를 확인해 보십시오.Swift를 통해 프로젝트에 추가할 수 있습니다.그런 다음 PM은 위의 예시와 동일하게 사용합니다.

import HandySwift    

delay(by: .seconds(1.5)) { 
    // delayed code
}

Swift 3에서도 이 작업을 수행할 수 있습니다.

이와 같이 지연 후 기능을 수행합니다.

override func viewDidLoad() {
    super.viewDidLoad()

    self.perform(#selector(ClassName.performAction), with: nil, afterDelay: 2.0)
}


     @objc func performAction() {
//This function will perform after 2 seconds
            print("Delayed")
        }

NSTimer

@은 @nneoneo를 사용하는 것을 했습니다.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(팔레의 답변과 같이) 또 다른 유효한 옵션입니다.하지만 취소는 어렵습니다.와 함께NSTimer

timer.invalidate()

사용.sleep는 특히 메인 스레드에서는 권장되지 않습니다.이는 스레드에서의 모든 작업을 중지하기 때문입니다.

자세한 내용은 여기를 참조하십시오.

Swift 3.0에서 다음 구현을 시도합니다.

func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { 
        completion()
    }
}

사용.

delayWithSeconds(1) {
   //Do something
}

지연을 1초 미만으로 설정할 필요가 있는 경우는 .seconds 파라미터를 설정할 필요가 없습니다.이게 누군가에게 도움이 됐으면 좋겠어요.

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
        // your code hear
})

지연기능을 쉽게 사용할 수 있도록 내선번호를 만들 수 있습니다(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)
    }
}

UIView Controller에서의 사용 방법

self.delay(0.1, closure: {
   //execute code
})

4초 타이머를 실행하는 가장 간단하고 최신 방법은 다음과 같습니다.

Task { 
    // Do something

    // Wait for 4 seconds
    try await Task.sleep(nanoseconds: 4_000_000_000) 

}

Swift 5.5의 새로운 동시성을 사용합니다.

애플의 콘클렌

코드가 이미 백그라운드 스레드에서 실행되고 있는 경우 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)
}

(코드가 메인 스레드에서 실행 중일 때 제안 사항은 다른 답변을 참조하십시오.)

DispatchQueue.global(qos: .background).async {
    sleep(4)
    print("Active after 4 sec, and doesn't block main")
    DispatchQueue.main.async{
        //do stuff in the main thread here
    }
}

간단한 시간 지연을 만들려면 Darwin을 가져온 다음 sleep(초)을 사용하여 지연을 수행할 수 있습니다.단, 단 몇 초밖에 걸리지 않기 때문에 보다 정확한 측정을 위해 다윈을 가져오고 매우 정확한 측정을 위해 usleep(백만 분의 1초)을 사용할 수 있습니다.이것을 테스트하기 위해서, 나는 다음과 같이 썼다.

import Darwin
print("This is one.")
sleep(1)
print("This is two.")
usleep(400000)
print("This is three.")

인쇄 후 1초간 기다렸다가 0.4초간 기다렸다가 인쇄합니다.모두 예상대로 작동했다.

사용.DispatchQueue.asyncAftermethod는 지정된 시간 후에 코드를 실행할 수 있습니다.예를 들어 실행한다....1초 후에 메인 스레드에 표시되는 것은 다음과 같습니다.

DispatchQueue.main.asyncAfter(deadline: .now() + 1) { ... }

내 핸디캡을 사용하여Delay래퍼 구조를 사용하면 보다 고급스럽게 실행할 수 있습니다.

struct Delay {

    @discardableResult
    init(_ timeInterval: TimeInterval, queue: DispatchQueue = .main, executingBlock: @escaping () -> Void) {
        queue.asyncAfter(deadline: .now() + timeInterval, execute: executingBlock)
    }

}

사용방법:

Delay(0.4) { ... }

스위프트 5 <

사용.Task.sleep작업 이외에는 어떤 코드도 차단하지 않습니다.그것은 매우 간단합니다.

//Delay task by 4 seconds:

Task {
    try await Task.sleep(nanoseconds: 4000000000)
    //Execute your code here
}

이는 스레드 실행에 영향을 주지 않는 지연을 추가하는 더 간단한 방법입니다.

let continueTime: Date = Calendar.current.date(byAdding: .second, value: 30, to: Date())!
while (Date() < continueTime) {
    //DO NOTHING
}

이전에 제안한 옵션의 대체 솔루션으로서DispatchGroupclass: 여러 비동기 태스크의 실행을 동기화하도록 설계되어 있습니다.

print("Start")
print(Date())

let delay = DispatchTimeInterval.seconds(3)
let group = DispatchGroup()
group.enter()
_ = group.wait(timeout: .now() + delay)

print("Finish")
print(Date())

갔지?enter()이 시작되었음을, method는 method 코드 실행이 시작되었음을 위해 됩니다.wait(timeout:)그룹 작업이 완료될 때까지 대기하는 메서드입니다.물론 이 예에서는 타임아웃이 지정되어 있기 때문에 이 문제는 발생하지 않습니다.이것은 필요한 지연과 동일합니다.

기성 도우미로 사용하기 편리합니다.

public class DispatchWait {
    private init () { }
    
    public static func `for` (_ interval: DispatchTimeInterval) {
        let group = DispatchGroup()
        group.enter()
        _ = group.wait(timeout: .now().advanced(by: interval))
    }
}

「 」의 DispatchWait:

print("Start")
print(Date())

DispatchWait.for(.seconds(3))

print("Finish")
print(Date())

의 정확도는 이며, 「」, 「지연」, 「지연」, 「지연」의 수 .wait(timeout:)method는 지정된 지연보다 훨씬 늦게 프로그램을 실행할 수 있도록 합니다.

또한 이 솔루션을 사용하면 별도의 폐쇄에서 코드를 실행할 필요 없이 현재 큐의 코드를 지연시킬 수 있습니다.

이것이 가장 간단하다

    delay(0.3, closure: {
        // put her any code you want to fire it with delay
        button.removeFromSuperview()   
    })

언급URL : https://stackoverflow.com/questions/27517632/how-to-create-a-delay-in-swift

반응형