딜레이 - serial vs concurrent queue ios




지연 후 블록을 어떻게 트리거합니까?-performSelector:withObject:afterDelay:? (12)

BlocksKit 프레임 워크에는 멋진 것이 있습니다.

BlocksKit

(그리고 클래스)

BBlocksKit.m

performSelector:withObject:afterDelay: 사용하는 것과 같이 지연 후에 기본 매개 변수를 사용하여 블록을 호출하는 방법이 있나요? int / double / float 와 같은 인수가 있습니까?


Jaime Cham의 답변을 확대하여 NSObject + Blocks 카테고리를 아래와 같이 만들었습니다. 나는이 메서드들이 기존의 performSelector: NSObject 메서드와 더 잘 performSelector: 느꼈다 performSelector:

NSObject + Blocks.h

#import <Foundation/Foundation.h>

@interface NSObject (Blocks)

- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay;

@end

NSObject + Blocks.m

#import "NSObject+Blocks.h"

@implementation NSObject (Blocks)

- (void)performBlock:(void (^)())block
{
    block();
}

- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay
{
    void (^block_)() = [block copy]; // autorelease this if you're not using ARC
    [self performSelector:@selector(performBlock:) withObject:block_ afterDelay:delay];
}

@end

다음과 같이 사용하십시오.

[anyObject performBlock:^{
    [anotherObject doYourThings:stuff];
} afterDelay:0.15];

Swift에 대해서는 dispatch_after 메소드를 사용하여 특별한 것이 아닌 전역 함수를 만들었습니다. 나는 읽기 쉽고 사용하기 쉽기 때문에 더 좋아합니다.

func performBlock(block:() -> Void, afterDelay delay:NSTimeInterval){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), block)
}

다음과 같이 사용할 수 있습니다.

performBlock({ () -> Void in
    // Perform actions
}, afterDelay: 0.3)

Swift에서 지연 후 블록을 트리거하는 방법은 다음과 같습니다.

runThisAfterDelay(seconds: 2) { () -> () in
    print("Prints this 2 seconds later in main queue")
}

/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue(), after)
}

내 레포 의 표준 기능으로 포함되어 있습니다.


dispatch_after 함수는 지정된 시간 후에 디스패치 대기열에 블록 객체를 전달합니다. 2.0 초 후에 몇 가지 UI 관련 작업을 수행하려면 아래 코드를 사용하십시오.

            let delay = 2.0
            let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
            let mainQueue = dispatch_get_main_queue()

            dispatch_after(delayInNanoSeconds, mainQueue, {

                print("Some UI related task after delay")
            })

신속한 3.0 :

            let dispatchTime: DispatchTime = DispatchTime.now() + Double(Int64(2.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
            DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: {

          })

나는 당신이 dispatch_after() 찾고 있다고 생각합니다. 블록에 매개 변수를 허용하지 않아도되지만 블록이 대신 로컬 범위에서 해당 변수를 캡처하도록 할 수 있습니다.

int parameter1 = 12;
float parameter2 = 144.1;

// Delay execution of my block for 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    NSLog(@"parameter1: %d parameter2: %f", parameter1, parameter2);
});

더보기 : https://developer.apple.com/documentation/dispatch/1452876-dispatch_after


신속한 3에서는 DispatchQueue.main.asyncAfter 함수를 사용하여 'n'초 지연 후에 모든 함수 나 액션을 트리거 할 수 있습니다. 여기 코드에서 우리는 1 초 후에 지연을 설정했습니다. 1 초의 지연 후 트리거하는이 함수 본문 내부의 함수를 호출합니다.

let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when) {

    // Trigger the function/action after the delay of 1Sec

}

아마도 GCD, 어딘가의 클래스 (예 : "Util") 또는 객체의 카테고리를 통과하는 것보다 간단합니다.

+ (void)runBlock:(void (^)())block
{
    block();
}
+ (void)runAfterDelay:(CGFloat)delay block:(void (^)())block 
{
    void (^block_)() = [[block copy] autorelease];
    [self performSelector:@selector(runBlock:) withObject:block_ afterDelay:delay];
}

그래서 사용하려면 :

[Util runAfterDelay:2 block:^{
    NSLog(@"two seconds later!");
}];

자신의 클래스에서 인수를 랩핑하거나 원시 유형에서 전달할 필요가없는 메소드에서 메소드 호출을 랩 할 수 있습니다. 그런 다음 해당 메서드를 지연 후 호출하고 해당 메서드 내에서 수행 할 선택기를 수행합니다.


지연 후에 작업을 큐에 넣는 Swift 3 방법이 있습니다.

DispatchQueue.main.asyncAfter(
  DispatchTime.now() + DispatchTimeInterval.seconds(2)) {
    // do work
}

귀찮은 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) { 
    // delayed code
}

코드를 다른 스레드지연 시키 려면 다음을 수행 하십시오 .

delay(bySeconds: 1.5, dispatchLevel: .background) { 
    // delayed code that will run on background thread
}

프레임 워크 가 더 편리한 기능을 가지고 HandySwift 를 체크 아웃 HandySwift . Carthage통해 프로젝트에 추가 한 다음 위의 예와 똑같이 사용할 수 있습니다.

import HandySwift    

delay(bySeconds: 1.5) { 
    // delayed code
}

Swift 3 및 Xcode 8.3.2

이 코드는 도움이 될 것입니다. 설명을 추가합니다.

// Create custom class, this will make your life easier
class CustomDelay {

    static let cd = CustomDelay()

    // This is your custom delay function
    func runAfterDelay(_ delay:Double, closure:@escaping ()->()) {
        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
    }
}


// here how to use it (Example 1)
class YourViewController: UIViewController {

    // example delay time 2 second
    let delayTime = 2.0

    override func viewDidLoad() {
        super.viewDidLoad()

        CustomDelay.cd.runAfterDelay(delayTime) {
            // This func will run after 2 second
            // Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
            self.runFunc()
        }
    }

    // example function 1
    func runFunc() {
        // do your method 1 here
    }
}

// here how to use it (Example 2)
class YourSecondViewController: UIViewController {

    // let say you want to user run function shoot after 3 second they tap a button

    // Create a button (This is programatically, you can create with storyboard too)
    let shootButton: UIButton = {
        let button = UIButton(type: .system)
        button.frame = CGRect(x: 15, y: 15, width: 40, height: 40) // Customize where do you want to put your button inside your ui
        button.setTitle("Shoot", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // create an action selector when user tap shoot button
        shootButton.addTarget(self, action: #selector(shoot), for: .touchUpInside)   
    }

    // example shoot function
    func shoot() {
        // example delay time 3 second then shoot
        let delayTime = 3.0

        // delay a shoot after 3 second
        CustomDelay.cd.runAfterDelay(delayTime) {
            // your shoot method here
            // Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
        }
    }   
}






objective-c-blocks