ios - देरी के बाद आप ब्लॉक को कैसे ट्रिगर करते हैं, जैसे-परफॉर्म चयनकर्ता: withObject: afterDelay:?




objective-c grand-central-dispatch (12)

देरी के बाद एक आदिम पैरामीटर के साथ ब्लॉक को कॉल करने का कोई तरीका है, जैसे performSelector:withObject:afterDelay: लेकिन int / double / float जैसे तर्क के साथ?


BlocksKit ढांचे में एक अच्छा है।

BlocksKit

(और कक्षा)

BBlocksKit.m


आप या तो अपनी खुद की कक्षा में तर्क लपेट सकते हैं, या विधि कॉल को विधि में लपेट सकते हैं जिसे आदिम प्रकार में पारित करने की आवश्यकता नहीं है। फिर अपनी देरी के बाद उस विधि को कॉल करें, और उस विधि के भीतर वह चयनकर्ता करें जिसे आप करना चाहते हैं।


जैम चाम के जवाब पर विस्तार करते हुए मैंने नीचे एक एनएसओब्जेक्ट + ब्लॉक श्रेणी बनाई। मुझे लगा कि इन तरीकों से मौजूदा प्रदर्शन से बेहतर मिलान किया गया performSelector: NSObject विधियां

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];

तेज़ 3 में, हम आसानी से 'n' सेकंड की देरी के बाद किसी भी फ़ंक्शन या एक्शन को ट्रिगर करने के लिए DispatchQueue.main.async फ़ंक्शन का उपयोग कर सकते हैं। यहां कोड में हमने 1 सेकंड के बाद देरी निर्धारित की है। आप इस फ़ंक्शन के बॉडी के अंदर कोई फ़ंक्शन कॉल करते हैं जो 1 सेकंड की देरी के बाद ट्रिगर होगा।

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

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

}

प्रेषण_फंक्शन फ़ंक्शन किसी दिए गए समय के बाद एक प्रेषण कतार में ब्लॉक ऑब्जेक्ट भेजता है। 2.0 सेकंड के बाद कुछ UI संबंधित tak करने के लिए नीचे कोड का उपयोग करें।

            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 का उपयोग कर सकते हैं। एक्सकोड में, dispatch_after टाइप करना प्रारंभ करें dispatch_after निम्न पर स्वत: पूर्ण करने के लिए Enter दबाएं:

यहां दो फ़्लोट्स के साथ "तर्क" के रूप में एक उदाहरण दिया गया है। आपको किसी भी प्रकार के मैक्रो पर भरोसा नहीं करना है, और कोड का इरादा स्पष्ट है:

स्विफ्ट 3, स्विफ्ट 4

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("Sum of times: \(time1 + time2)")
}

स्विफ्ट 2

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
        println("Sum of times: \(time1 + time2)")
}

उद्देश्य सी

CGFloat time1 = 3.49;
CGFloat time2 = 8.13;

// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    CGFloat newTime = time1 + time2;
    NSLog(@"New time: %f", newTime);
});

मेरा मानना ​​है कि लेखक एक अंशकालिक समय (देरी) की प्रतीक्षा करने के लिए नहीं पूछ रहा है, बल्कि इसके बजाय चयनकर्ता के तर्क के रूप में एक स्केलर को कैसे पास किया जाए (ऑब्जेक्ट :) और आधुनिक उद्देश्य सी में सबसे तेज़ तरीका है:

[obj performSelector:...  withObject:@(0.123123123) afterDelay:10]

आपके चयनकर्ता को अपना पैरामीटर एनएसएनंबर में बदलना होगा, और फ्लोट वैल्यू या डबलव्यू जैसे चयनकर्ता का उपयोग करके मूल्य पुनर्प्राप्त करना होगा।


यहां मेरे 2 सेंट = 5 तरीके हैं;)

मुझे इन विवरणों को समाहित करना पसंद है और ऐपकोड मुझे बताता है कि मेरे वाक्य कैसे समाप्त करें।

void dispatch_after_delay(float delayInSeconds, dispatch_queue_t queue, dispatch_block_t block) {
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, queue, block);
}

void dispatch_after_delay_on_main_queue(float delayInSeconds, dispatch_block_t block) {
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_after_delay(delayInSeconds, queue, block);
}

void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}

void dispatch_async_on_background_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}

void dispatch_async_on_main_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_main_queue(), block);
}

शायद जीसीडी के माध्यम से कहीं भी एक कक्षा में (उदाहरण के लिए "उपयोग"), या ऑब्जेक्ट पर एक श्रेणी में जाने से सरल है:

+ (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!");
}];

स्विफ्ट के लिए मैंने 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)

कष्टप्रद जीसीडी कॉल को बार-बार बनाने से रोकने के लिए यहां एक आसान सहायक है:

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 । आप इसे अपने प्रोजेक्ट में कार्थेज के माध्यम से जोड़ सकते हैं, फिर इसे ऊपर दिए गए उदाहरणों में बिल्कुल उपयोग करें:

import HandySwift    

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

स्विफ्ट 3 और एक्सकोड 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