杨锴
2025-04-16 09a372bc45fde16fd42257ab6f78b8deeecf720b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * This file is part of the SDWebImage package.
 * (c) Olivier Poitrey <rs@dailymotion.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
 
 
#import "SDCallbackQueue.h"
 
@interface SDCallbackQueue ()
 
@property (nonatomic, strong, nonnull) dispatch_queue_t queue;
 
@end
 
static void * SDCallbackQueueKey = &SDCallbackQueueKey;
static void SDReleaseBlock(void *context) {
    CFRelease(context);
}
 
static void SDSafeExecute(SDCallbackQueue *callbackQueue, dispatch_block_t _Nonnull block, BOOL async) {
    // Extendc gcd queue's life cycle
    dispatch_queue_t queue = callbackQueue.queue;
    // Special handle for main queue label only (custom queue can have the same label)
    const char *label = dispatch_queue_get_label(queue);
    if (label && label == dispatch_queue_get_label(dispatch_get_main_queue())) {
        const char *currentLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
        if (label == currentLabel) {
            block();
            return;
        }
    }
    // Check specific to detect queue equal
    void *specific = dispatch_queue_get_specific(queue, SDCallbackQueueKey);
    if (specific && CFGetTypeID(specific) == CFUUIDGetTypeID()) {
        void *currentSpecific = dispatch_get_specific(SDCallbackQueueKey);
        if (currentSpecific && CFGetTypeID(currentSpecific) == CFUUIDGetTypeID() && CFEqual(specific, currentSpecific)) {
            block();
            return;
        }
    }
    if (async) {
        dispatch_async(queue, block);
    } else {
        dispatch_sync(queue, block);
    }
}
 
@implementation SDCallbackQueue
 
- (instancetype)initWithDispatchQueue:(dispatch_queue_t)queue {
    self = [super init];
    if (self) {
        NSCParameterAssert(queue);
        CFUUIDRef UUID = CFUUIDCreate(kCFAllocatorDefault);
        dispatch_queue_set_specific(queue, SDCallbackQueueKey, (void *)UUID, SDReleaseBlock);
        _queue = queue;
    }
    return self;
}
 
+ (SDCallbackQueue *)mainQueue {
    static dispatch_once_t onceToken;
    static SDCallbackQueue *queue;
    dispatch_once(&onceToken, ^{
        queue = [[SDCallbackQueue alloc] initWithDispatchQueue:dispatch_get_main_queue()];
    });
    return queue;
}
 
+ (SDCallbackQueue *)currentQueue {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    SDCallbackQueue *queue = [[SDCallbackQueue alloc] initWithDispatchQueue:dispatch_get_current_queue()];
#pragma clang diagnostic pop
    return queue;
}
 
+ (SDCallbackQueue *)globalQueue {
    SDCallbackQueue *queue = [[SDCallbackQueue alloc] initWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];
    return queue;
}
 
- (void)sync:(nonnull dispatch_block_t)block {
    switch (self.policy) {
        case SDCallbackPolicySafeExecute:
            SDSafeExecute(self, block, NO);
            break;
        case SDCallbackPolicyDispatch:
            dispatch_sync(self.queue, block);
            break;
        case SDCallbackPolicyInvoke:
            block();
            break;
        default:
            SDSafeExecute(self, block, NO);
            break;
    }
}
 
- (void)async:(nonnull dispatch_block_t)block {
    switch (self.policy) {
        case SDCallbackPolicySafeExecute:
            SDSafeExecute(self, block, YES);
            break;
        case SDCallbackPolicyDispatch:
            dispatch_async(self.queue, block);
            break;
        case SDCallbackPolicyInvoke:
            block();
            break;
        default:
            SDSafeExecute(self, block, YES);
            break;
    }
}
 
@end