IT story

스위프트에서 지연을 만드는 방법?

hot-time 2020. 4. 19. 13:56
반응형

스위프트에서 지연을 만드는 방법?


특정 시점에서 앱을 일시 중지하고 싶습니다. 즉, 앱에서 코드를 실행하고 특정 지점에서 4 초 동안 일시 중지 한 다음 나머지 코드를 계속 실행하려고합니다. 어떻게해야합니까?

Swift를 사용하고 있습니다.


UI 스레드에서 호출 된 경우 프로그램을 잠그는 절전 모드 대신 NSTimer디스패치 타이머 사용을 고려하십시오 .

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

... {
    sleep(4)
}

이것은 sleepUNIX 기능을 사용합니다 .


dispatch_after대부분의 경우 sleep(time)슬립을 수행하는 스레드가 다른 작업을 수행하지 못하도록 차단하는 것보다 블록을 사용하는 것이 좋습니다 . dispatch_after작업중 인 스레드를 사용할 때 차단되지 않으므로 그 동안 다른 작업을 수행 할 수 있습니다.
응용 프로그램의 주요 스레드에서 작업하는 경우 sleep(time)해당 시간 동안 UI가 응답하지 않기 때문에 앱의 사용자 경험에 좋지 않습니다.

스레드 후 중단하는 대신 코드 블록 실행을 예약 한 후 전달 :

스위프트 ≥ 3.0

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

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

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사용자 상호 작용을 비활성화하므로 화면이 " 정지 (실제로는 아님)"하고 사용자 경험이 좋지 않습니다. 다른 세 가지 방법은 화면을 정지시키지 않지만 여러 번 트리거 할 수 있으며 대부분의 경우 사용자가 다시 전화를 걸기 전에 전화를받을 때까지 기다립니다.

따라서 더 나은 디자인은 화면 차단 기능이있는 세 가지 비동기 방법 중 하나를 사용하는 것입니다. 사용자가 버튼을 클릭하면 상단에 회전 활동 표시기가있는 반투명보기로 전체 화면을 덮어 버튼 클릭이 처리되고 있음을 사용자에게 알립니다. 그런 다음 콜백 기능에서보기 및 표시기를 제거하여 사용자에게 조치가 올바르게 처리되었음을 알리십시오.


내가 사용하는 것을의 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
}

좀 더 편리한 기능을 가진 프레임 워크 를 선호한다면 HandySwift 를 확인 하십시오 . Carthage 또는 Accio통해 프로젝트에 추가 한 다음 위의 예와 동일하게 사용할 수 있습니다.

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

@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 및 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을 사용하지 마십시오 .


Swift 3.0에서 다음 구현을 시도하십시오

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

용법

delayWithSeconds(1) {
   //Do something
}

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

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

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

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

반응형