QNSingleFlight.m 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. //
  2. // QNSingleFlight.m
  3. // QiniuSDK
  4. //
  5. // Created by yangsen on 2021/1/4.
  6. // Copyright © 2021 Qiniu. All rights reserved.
  7. //
  8. #import "QNDefine.h"
  9. #import "QNSingleFlight.h"
  10. @interface QNSingleFlightTask : NSObject
  11. @property(nonatomic, copy)QNSingleFlightComplete complete;
  12. @end
  13. @implementation QNSingleFlightTask
  14. @end
  15. @interface QNSingleFlightCall : NSObject
  16. @property(nonatomic, assign)BOOL isComplete;
  17. @property(nonatomic, strong)NSMutableArray <QNSingleFlightTask *> *tasks;
  18. @property(nonatomic, strong)id value;
  19. @property(nonatomic, strong)NSError *error;
  20. @end
  21. @implementation QNSingleFlightCall
  22. @end
  23. @interface QNSingleFlight()
  24. @property(nonatomic, strong)NSMutableDictionary <NSString *, QNSingleFlightCall *> *callInfo;
  25. @end
  26. @implementation QNSingleFlight
  27. - (void)perform:(NSString * _Nullable)key
  28. action:(QNSingleFlightAction _Nonnull)action
  29. complete:(QNSingleFlightComplete _Nullable)complete {
  30. if (!action) {
  31. return;
  32. }
  33. BOOL isFirstTask = false;
  34. BOOL shouldComplete = false;
  35. QNSingleFlightCall *call = nil;
  36. @synchronized (self) {
  37. if (!self.callInfo) {
  38. self.callInfo = [NSMutableDictionary dictionary];
  39. }
  40. if (key) {
  41. call = self.callInfo[key];
  42. }
  43. if (!call) {
  44. call = [[QNSingleFlightCall alloc] init];
  45. call.isComplete = false;
  46. call.tasks = [NSMutableArray array];
  47. if (key) {
  48. self.callInfo[key] = call;
  49. }
  50. isFirstTask = true;
  51. }
  52. @synchronized (call) {
  53. shouldComplete = call.isComplete;
  54. if (!shouldComplete) {
  55. QNSingleFlightTask *task = [[QNSingleFlightTask alloc] init];
  56. task.complete = complete;
  57. [call.tasks addObject:task];
  58. }
  59. }
  60. }
  61. if (shouldComplete) {
  62. if (complete) {
  63. complete(call.value, call.error);
  64. }
  65. return;
  66. }
  67. if (!isFirstTask) {
  68. return;
  69. }
  70. kQNWeakSelf;
  71. kQNWeakObj(call);
  72. action(^(id value, NSError *error){
  73. kQNStrongSelf;
  74. kQNStrongObj(call);
  75. NSArray *tasksP = nil;
  76. @synchronized (call) {
  77. if (call.isComplete) {
  78. return;
  79. }
  80. call.isComplete = true;
  81. call.value = value;
  82. call.error = error;
  83. tasksP = [call.tasks copy];
  84. }
  85. if (key) {
  86. @synchronized (self) {
  87. [self.callInfo removeObjectForKey:key];
  88. }
  89. }
  90. for (QNSingleFlightTask *task in tasksP) {
  91. if (task.complete) {
  92. task.complete(value, error);
  93. }
  94. }
  95. });
  96. }
  97. @end