जवाबों:
मुझे लगता है कि आप ढूंढ रहे हैं 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
dispatch_time(DISPATCH_TIME_NOW, 10ull * NSEC_PER_SEC)
स्निपेट गंदा है। क्या इसके लिए कोई क्लीनर रास्ता नहीं है?
dispatch_get_current_queue()
हमेशा उस कतार को लौटाता है जिससे कोड चलाया जा रहा है। इसलिए जब यह कोड मुख्य धागे से चलाया जाता है, तो ब्लॉक को मुख्य धागे पर भी निष्पादित किया जाएगा।
dispatch_get_current_queue()
अब पदावनत किया गया है
आप dispatch_after
बाद में किसी ब्लॉक को कॉल करने के लिए उपयोग कर सकते हैं । Xcode में, टाइप करना शुरू करें dispatch_after
और Enter
निम्नलिखित के लिए स्वतः पूर्ण करें:
यहां दो तर्कों के साथ एक उदाहरण दिया गया है "तर्क।" आपको किसी भी प्रकार के मैक्रो पर भरोसा करने की आवश्यकता नहीं है, और कोड का इरादा काफी स्पष्ट है:
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
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);
});
NSEC_PER_SEC * 0.5
रूप में ही काम करेगा NSEC_PER_MSEC * 500
। जब आप ध्यान दें कि dispatch_time
64-बिट पूर्णांक की अपेक्षा करता है, तो यह मान लें कि यह अपेक्षा है कि यह नैनोसेकंड में है। NSEC_PER_SEC
के रूप में परिभाषित किया गया है 1000000000ull
, और एक फ़्लोटिंग-पॉइंट स्थिरांक के साथ गुणा 0.5
करना, स्पष्ट रूप से फ़्लोटिंग-पॉइंट अंकगणित, पैदावार करना 500000000.0
, इससे पहले कि यह स्पष्ट रूप से 64-बिट पूर्णांक में वापस डाली जाए। तो यह एक अंश का उपयोग करने के लिए पूरी तरह से स्वीकार्य है NSEC_PER_SEC
।
Xcode बिल्ट-इन कोड स्निपेट लाइब्रेरी का उपयोग करने के बारे में कैसे?
स्विफ्ट के लिए अपडेट करें:
कई वोटों ने मुझे इस उत्तर को अपडेट करने के लिए प्रेरित किया।
बिल्ड-इन Xcode कोड स्निपेट लाइब्रेरी में dispatch_after
केवल objective-c
भाषा के लिए है। लोगों को भी अपने स्वयं के बना सकते हैं कस्टम कोड स्निपेट के लिए Swift
।
इसे Xcode में लिखें।
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(<#delayInSeconds#> * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), {
<#code to be executed after a specified delay#>
})
इस कोड को खींचें और इसे कोड स्निपेट लाइब्रेरी क्षेत्र में छोड़ दें।
कोड स्निपेट सूची के नीचे एक नई इकाई होगी, जिसका नाम होगा My Code Snippet
। इसे एक शीर्षक के लिए संपादित करें। सुझाव के लिए जैसे ही आप Xcode भरें, उसमें लिखें Completion Shortcut
।
अधिक जानकारी के लिए CreateaCustomCodeSnippet देखें ।
इस कोड को खींचें और इसे कोड स्निपेट लाइब्रेरी क्षेत्र में छोड़ दें।
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
<#code to be executed after a specified delay#>
}
Jaime Cham के जवाब पर विस्तार करते हुए मैंने नीचे एक NSObject + Blocks श्रेणी बनाई। मैंने महसूस किया कि ये विधियाँ मौजूदा 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];
delay
का होना चाहिए NSTimeInterval
(जो एक है double
)। #import <UIKit/UIKit.h>
आवश्यकता नहीं है। और, मैं नहीं देखता कि - (void)performBlock:(void (^)())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)
after
। फिर आप लिख सकते हैं:after(2.0){ print("do somthing") }
यहाँ मेरे 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);
}
PerformSelector: WithObject हमेशा एक ऑब्जेक्ट लेता है, इसलिए int / double / float आदि जैसे तर्क पास करने के लिए ..... आप इस तरह से कुछ का उपयोग कर सकते हैं।
// NSNumber एक वस्तु है ।।
[self performSelector:@selector(setUserAlphaNumber:)
withObject: [NSNumber numberWithFloat: 1.0f]
afterDelay:1.5];
-(void) setUserAlphaNumber: (NSNumber*) number{
[txtUsername setAlpha: [number floatValue] ];
}
उसी तरह से आप [NSNumber numberWithInt:] आदि का उपयोग कर सकते हैं .... और प्राप्त करने की विधि में आप संख्या को अपने प्रारूप में [संख्या int] या [संख्या डबल] के रूप में परिवर्तित कर सकते हैं।
Dispatch_after function एक निश्चित समय अवधि के बाद प्रेषण कतार में एक ब्लॉक ऑब्जेक्ट भेजता है। 2.0 सेकंड के बाद कुछ यूआई से संबंधित प्रदर्शन करने के लिए नीचे दिए गए कोड का उपयोग करें।
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: {
})
mainQueue,
इसके बजायmainQueue)
बार-बार कष्टप्रद 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
}
यदि आप एक ऐसी फ्रेमवर्क पसंद करते हैं जिसमें कुछ अधिक उपयोगी विशेषताएं हैं तो हैंडवाइस लिफ्ट चेकआउट करें । आप इसे Carthage के माध्यम से अपनी परियोजना में जोड़ सकते हैं, फिर इसे ऊपर दिए गए उदाहरणों की तरह उपयोग कर सकते हैं:
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
स्विफ्ट 3 में, हम 'n' सेकंड की देरी के बाद किसी भी फ़ंक्शन या क्रिया को ट्रिगर करने के लिए DispatchQueue.main.asyncAfter फ़ंक्शन का उपयोग कर सकते हैं। यहां कोड में हमने 1 सेकंड के बाद देरी की है। आप इस फ़ंक्शन के शरीर के अंदर किसी भी फ़ंक्शन को कॉल करते हैं जो 1 सेकंड की देरी के बाद ट्रिगर होगा।
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when) {
// Trigger the function/action after the delay of 1Sec
}
आप या तो अपनी कक्षा में तर्क को लपेट सकते हैं, या विधि कॉल को ऐसी विधि में लपेट सकते हैं जिसे आदिम प्रकार में पारित करने की आवश्यकता नहीं है। फिर अपने विलंब के बाद उस पद्धति को कॉल करें, और उस पद्धति के भीतर आप जिस चयनकर्ता को प्रदर्शन करना चाहते हैं उसे करें।
यहां बताया गया है कि आप स्विफ्ट में देरी के बाद ब्लॉक को कैसे ट्रिगर कर सकते हैं:
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)
}
यह मेरे रेपो में एक मानक कार्य के रूप में शामिल है ।
स्विफ्ट 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 :)
}
}
}
मेरा मानना है कि लेखक यह नहीं पूछ रहा है कि भिन्नात्मक समय (देरी) का इंतजार कैसे किया जाए, बल्कि चयनकर्ता के तर्क के रूप में एक स्केलर को कैसे पास किया जाए (withObject :) और आधुनिक उद्देश्य C में सबसे तेज़ तरीका है:
[obj performSelector:... withObject:@(0.123123123) afterDelay:10]
आपके चयनकर्ता को अपने पैरामीटर को NSNumber में बदलना होगा, और फ्लोटवैल्यू या वीवीयू जैसे चयनकर्ता का उपयोग करके मान प्राप्त करना होगा