इस उत्तर यहां पोस्ट किया जाना चाहिए:: - मेरे मामले में बस से पहले अगले शेड्यूल करते समय कॉल देरी cancel dispatch_after() method?, लेकिन वह (यह वास्तव में नहीं है) डुप्लिकेट के रूप में बंद है। वैसे भी, यह एक ऐसा स्थान है जहां Google "dispatch_after cancel" के लिए रिटर्न देता है, इसलिए ...
यह प्रश्न बहुत मौलिक है और मुझे यकीन है कि ऐसे लोग हैं जो विभिन्न प्लेटफ़ॉर्म-विशिष्टताओं का उपयोग किए बिना वास्तव में सामान्य समाधान चाहते हैं रनलोप टाइमर, इंस्टेंस-निहित बूलियन और/या भारी ब्लॉक जादू। जीसीडी नियमित सी पुस्तकालय के रूप में इस्तेमाल किया जा सकता है और टाइमर के रूप में ऐसी कोई चीज़ नहीं हो सकती है।
सौभाग्य से, किसी भी जीवनकाल योजना में किसी भी प्रेषण ब्लॉक को रद्द करने का एक तरीका है।
- हमें प्रत्येक ब्लॉक को एक गतिशील हैंडल संलग्न करना है जिसे हम dispatch_after (या dispatch_async, वास्तव में मायने रखते हैं) में पास नहीं करते हैं।
- यह संभाल तब तक मौजूद होना चाहिए जब तक कि ब्लॉक वास्तव में निकाल दिया न जाए।
- इस हैंडल के लिए मेमोरी प्रबंधन इतना स्पष्ट नहीं है - अगर ब्लॉक हैंडल को मुक्त करता है, तो हम बाद में पॉइंटर को खतरे में डाल सकते हैं, लेकिन अगर हम इसे मुक्त करते हैं, तो ब्लॉक बाद में ऐसा कर सकता है।
- तो, हमें मांग पर स्वामित्व पास करना होगा।
- 2 ब्लॉक हैं - एक नियंत्रण ब्लॉक है जो किसी भी तरह से आग लगता है और दूसरा पेलोड है जिसे रद्द किया जा सकता है।
struct async_handle {
char didFire; // control block did fire
char shouldCall; // control block should call payload
char shouldFree; // control block is owner of this handle
};
static struct async_handle *
dispatch_after_h(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t payload)
{
struct async_handle *handle = malloc(sizeof(*handle));
handle->didFire = 0;
handle->shouldCall = 1; // initially, payload should be called
handle->shouldFree = 0; // and handles belong to owner
payload = Block_copy(payload);
dispatch_after(when, queue, ^{
// this is a control block
printf("[%p] (control block) call=%d, free=%d\n",
handle, handle->shouldCall, handle->shouldFree);
handle->didFire = 1;
if (handle->shouldCall) payload();
if (handle->shouldFree) free(handle);
Block_release(payload);
});
return handle; // to owner
}
void
dispatch_cancel_h(struct async_handle *handle)
{
if (handle->didFire) {
printf("[%p] (owner) too late, freeing myself\n", handle);
free(handle);
}
else {
printf("[%p] (owner) set call=0, free=1\n", handle);
handle->shouldCall = 0;
handle->shouldFree = 1; // control block is owner now
}
}
यह है कि।
मुख्य बिंदु यह है कि "मालिक" को हैंडल एकत्र करना चाहिए जब तक कि उन्हें अब और आवश्यकता न हो। dispatch_cancel_h() एक हैंडल के लिए [संभावित रूप से स्थगित] विनाशक के रूप में काम करता है।
सी मालिक उदाहरण:
size_t n = 100;
struct after_handle *handles[n];
for (size_t i = 0; i < n; i++)
handles[i] = dispatch_after_h(when, queue, ^{
printf("working\n");
sleep(1);
});
...
// cancel blocks when lifetime is over!
for (size_t i = 0; i < n; i++) {
dispatch_cancel_h(handles[i]);
handles[i] = NULL; // not our responsibility now
}
ऑब्जेक्टिव-सी एआरसी उदाहरण:
- (id)init
{
self = [super init];
if (self) {
queue = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL);
handles = [[NSMutableArray alloc] init];
}
return self;
}
- (void)submitBlocks
{
for (int i = 0; i < 100; i++) {
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (random() % 10) * NSEC_PER_SEC);
__unsafe_unretained id this = self; // prevent retain cycles
struct async_handle *handle = dispatch_after_h(when, queue, ^{
printf("working (%d)\n", [this someIntValue]);
sleep(1);
});
[handles addObject:[NSValue valueWithPointer:handle]];
}
}
- (void)cancelAnyBlock
{
NSUInteger i = random() % [handles count];
dispatch_cancel_h([handles[i] pointerValue]);
[handles removeObjectAtIndex:i];
}
- (void)dealloc
{
for (NSValue *value in handles) {
struct async_handle *handle = [value pointerValue];
dispatch_cancel_h(handle);
}
// now control blocks will never call payload that
// dereferences now-dangling self/this.
}
नोट्स:
- dispatch_after() मूल रूप से, कतार को बरकरार रखे हुए है, तो यह सब जब तक उपलब्ध नहीं होगा नियंत्रण ब्लॉक निष्पादित कर रहे हैं।
- async_handles को मुक्त किया जाता है अगर पेलोड रद्द हो जाता है (या मालिक का जीवनकाल खत्म हो गया था) और नियंत्रण ब्लॉक निष्पादित किया गया था।
- async_handle की गतिशील मेमोरी ओवरहेड dispatch_after() और dispatch_queue_t की आंतरिक संरचनाओं की तुलना में बिल्कुल मामूली है, जो सबमिट किए जाने वाले ब्लॉक की वास्तविक सरणी बनाए रखती है और उपयुक्त होने पर उन्हें हटा देती है।
- आप देख सकते हैं कि चाहिएकॉल और चाहिएफ्री वास्तव में एक ही उलटा झंडा है। लेकिन यदि आपका मालिक "स्वयं" या अन्य मालिक से संबंधित डेटा पर निर्भर नहीं है, तो आपके मालिक का उदाहरण स्वामित्व और यहां तक कि - [dealloc] खुद को पेलोड ब्लॉक को रद्द किए बिना भी पारित कर सकता है। इसे dispatch_cancel_h() को अतिरिक्त shouldCallAnyway तर्क के साथ कार्यान्वित किया जा सकता है।
- चेतावनी नोट: इस समाधान में भी डीएक्सएक्सजेड झंडे के सिंक्रनाइज़ेशन की कमी है और नियंत्रण ब्लॉक और रद्दीकरण दिनचर्या के बीच दौड़ हो सकती है। OSAtomicOr32Barrier() & सह सिंक्रनाइज़ करने के लिए सह का उपयोग करें।
आप ठीक कह रहे हैं, कि बेहतर समाधान है कर रहा है! –
बहुत बहुत धन्यवाद! बहुत आसन! मुझे अपने बारे में सोचना चाहिए था –