Skip to content

Commit ed1f0f8

Browse files
committed
Added SDCallbackPolicyMainAsyncSafe which has better compatibility for UI-related code logic
Handled two cases in real-world app
1 parent b4eeb0f commit ed1f0f8

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

SDWebImage/Core/SDCallbackQueue.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ typedef NS_ENUM(NSUInteger, SDCallbackPolicy) {
1616
/// Follow async/sync using the correspond `dispatch_async`/`dispatch_sync` to dispatch block on queue
1717
SDCallbackPolicyDispatch = 1,
1818
/// Ignore any async/sync and just directly invoke `block` in current queue (without `dispatch_async`/`dispatch_sync`)
19-
SDCallbackPolicyInvoke = 2
19+
SDCallbackPolicyInvoke = 2,
20+
/// Ensure callback in main queue and main thread, will do `dispatch_async` if the current queue is not main queue; else do invoke `block`. Never use `dispatch_sync`, suitable for UI-related work
21+
SDCallbackPolicyMainAsyncSafe = 3
2022
};
2123

2224
/// SDCallbackQueue is a wrapper used to control how the completionBlock should perform on queues, used by our `Cache`/`Manager`/`Loader`.
@@ -32,7 +34,7 @@ typedef NS_ENUM(NSUInteger, SDCallbackPolicy) {
3234
/// The global concurrent queue (user-initiated QoS). Using `dispatch_get_global_queue`.
3335
@property (nonnull, class, readonly) SDCallbackQueue *globalQueue;
3436

35-
/// The current queue's callback policy, defaults to `SDCallbackPolicySafeExecute`, which behaves like the old macro `dispatch_main_async_safe`
37+
/// The current queue's callback policy, defaults to `SDCallbackPolicyMainAsyncSafe`, which behaves like the old macro `dispatch_main_async_safe`
3638
@property (assign, readwrite) SDCallbackPolicy policy;
3739

3840
- (nonnull instancetype)init NS_UNAVAILABLE;

SDWebImage/Core/SDCallbackQueue.m

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
@interface SDCallbackQueue ()
1313

1414
@property (nonatomic, strong, nonnull) dispatch_queue_t queue;
15+
@property (nonatomic, strong, nonnull) NSThread *thread;
1516

1617
@end
1718

@@ -20,8 +21,21 @@ static void SDReleaseBlock(void *context) {
2021
CFRelease(context);
2122
}
2223

24+
static inline void SDSafeMainAsync(dispatch_block_t _Nonnull block) {
25+
if (NSThread.isMainThread) {
26+
// Match exists `dispatch_main_async_safe` behavior
27+
const char *currentLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
28+
const char *mainLabel = dispatch_queue_get_label(dispatch_get_main_queue());
29+
if (mainLabel == currentLabel) {
30+
block();
31+
return;
32+
}
33+
}
34+
dispatch_async(dispatch_get_main_queue(), block);
35+
}
36+
2337
static void SDSafeExecute(SDCallbackQueue *callbackQueue, dispatch_block_t _Nonnull block, BOOL async) {
24-
// Extendc gcd queue's life cycle
38+
// Extend gcd queue's life cycle
2539
dispatch_queue_t queue = callbackQueue.queue;
2640
// Special handle for main queue label only (custom queue can have the same label)
2741
const char *label = dispatch_queue_get_label(queue);
@@ -57,6 +71,9 @@ - (instancetype)initWithDispatchQueue:(dispatch_queue_t)queue {
5771
CFUUIDRef UUID = CFUUIDCreate(kCFAllocatorDefault);
5872
dispatch_queue_set_specific(queue, SDCallbackQueueKey, (void *)UUID, SDReleaseBlock);
5973
_queue = queue;
74+
_policy = SDCallbackPolicyMainAsyncSafe;
75+
// global queue can execute on main thread, like call `dispatch_sync(globalQueue)` in main thread
76+
_thread = NSThread.currentThread;
6077
}
6178
return self;
6279
}
@@ -94,6 +111,9 @@ - (void)sync:(nonnull dispatch_block_t)block {
94111
case SDCallbackPolicyInvoke:
95112
block();
96113
break;
114+
case SDCallbackPolicyMainAsyncSafe:
115+
SDSafeMainAsync(block);
116+
break;
97117
default:
98118
SDSafeExecute(self, block, NO);
99119
break;
@@ -111,6 +131,9 @@ - (void)async:(nonnull dispatch_block_t)block {
111131
case SDCallbackPolicyInvoke:
112132
block();
113133
break;
134+
case SDCallbackPolicyMainAsyncSafe:
135+
SDSafeMainAsync(block);
136+
break;
114137
default:
115138
SDSafeExecute(self, block, YES);
116139
break;

0 commit comments

Comments
 (0)