Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2019 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.h"
16
 
17
#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation_Private.h"
18
 
19
#define FIRCLS_DISPATCH_QUEUES_AS_OBJECTS OS_OBJECT_USE_OBJC_RETAIN_RELEASE
20
 
21
const NSUInteger FIRCLSCompoundOperationErrorCodeCancelled = UINT_MAX - 1;
22
const NSUInteger FIRCLSCompoundOperationErrorCodeSuboperationFailed = UINT_MAX - 2;
23
 
24
NSString *const FIRCLSCompoundOperationErrorUserInfoKeyUnderlyingErrors =
25
    @"com.google.firebase.crashlytics.FIRCLSCompoundOperation.error.user-info-key.underlying-"
26
    @"errors";
27
 
28
static NSString *const FIRCLSCompoundOperationErrorDomain =
29
    @"com.google.firebase.crashlytics.FIRCLSCompoundOperation.error";
30
static char *const FIRCLSCompoundOperationCountingQueueLabel =
31
    "com.google.firebase.crashlytics.FIRCLSCompoundOperation.dispatch-queue.counting-queue";
32
 
33
@interface FIRCLSCompoundOperation ()
34
 
35
@property(strong, nonatomic, readwrite) NSOperationQueue *compoundQueue;
36
@property(assign, nonatomic) NSUInteger completedOperations;
37
@property(strong, nonatomic) NSMutableArray *errors;
38
#if FIRCLS_DISPATCH_QUEUES_AS_OBJECTS
39
@property(strong, nonatomic) dispatch_queue_t countingQueue;
40
#else
41
@property(assign, nonatomic) dispatch_queue_t countingQueue;
42
#endif
43
 
44
@end
45
 
46
@implementation FIRCLSCompoundOperation
47
 
48
- (instancetype)init {
49
  self = [super init];
50
  if (!self) {
51
    return nil;
52
  }
53
 
54
  _compoundQueue = [[NSOperationQueue alloc] init];
55
  _completedOperations = 0;
56
  _errors = [NSMutableArray array];
57
  _countingQueue =
58
      dispatch_queue_create(FIRCLSCompoundOperationCountingQueueLabel, DISPATCH_QUEUE_SERIAL);
59
 
60
  return self;
61
}
62
 
63
#if !FIRCLS_DISPATCH_QUEUES_AS_OBJECTS
64
- (void)dealloc {
65
  if (_countingQueue) {
66
    dispatch_release(_countingQueue);
67
  }
68
}
69
#endif
70
 
71
- (void)main {
72
  for (FIRCLSFABAsyncOperation *operation in self.operations) {
73
    [self injectCompoundAsyncCompletionInOperation:operation];
74
    [self injectCompoundSyncCompletionInOperation:operation];
75
 
76
    [self.compoundQueue addOperation:operation];
77
  }
78
}
79
 
80
- (void)cancel {
81
  if (self.compoundQueue.operations.count > 0) {
82
    [self.compoundQueue cancelAllOperations];
83
    dispatch_sync(self.countingQueue, ^{
84
      [self attemptCompoundCompletion];
85
    });
86
  } else {
87
    for (NSOperation *operation in self.operations) {
88
      [operation cancel];
89
    }
90
 
91
    // we have to add the operations to the queue in order for their isFinished property to be set
92
    // to true.
93
    [self.compoundQueue addOperations:self.operations waitUntilFinished:NO];
94
  }
95
  [super cancel];
96
}
97
 
98
- (void)injectCompoundAsyncCompletionInOperation:(FIRCLSFABAsyncOperation *)operation {
99
  __weak FIRCLSCompoundOperation *weakSelf = self;
100
  FIRCLSFABAsyncOperationCompletionBlock originalAsyncCompletion = [operation.asyncCompletion copy];
101
  FIRCLSFABAsyncOperationCompletionBlock completion = ^(NSError *error) {
102
    __strong FIRCLSCompoundOperation *strongSelf = weakSelf;
103
 
104
    if (originalAsyncCompletion) {
105
      dispatch_sync(strongSelf.countingQueue, ^{
106
        originalAsyncCompletion(error);
107
      });
108
    }
109
 
110
    [strongSelf updateCompletionCountsWithError:error];
111
  };
112
  operation.asyncCompletion = completion;
113
}
114
 
115
- (void)injectCompoundSyncCompletionInOperation:(FIRCLSFABAsyncOperation *)operation {
116
  __weak FIRCLSCompoundOperation *weakSelf = self;
117
  void (^originalSyncCompletion)(void) = [operation.completionBlock copy];
118
  void (^completion)(void) = ^{
119
    __strong FIRCLSCompoundOperation *strongSelf = weakSelf;
120
 
121
    if (originalSyncCompletion) {
122
      dispatch_sync(strongSelf.countingQueue, ^{
123
        originalSyncCompletion();
124
      });
125
    }
126
 
127
    dispatch_sync(strongSelf.countingQueue, ^{
128
      [strongSelf attemptCompoundCompletion];
129
    });
130
  };
131
  operation.completionBlock = completion;
132
}
133
 
134
- (void)updateCompletionCountsWithError:(NSError *)error {
135
  dispatch_sync(self.countingQueue, ^{
136
    if (!error) {
137
      self.completedOperations += 1;
138
    } else {
139
      [self.errors addObject:error];
140
    }
141
  });
142
}
143
 
144
- (void)attemptCompoundCompletion {
145
  if (self.isCancelled) {
146
    [self finishWithError:[NSError errorWithDomain:FIRCLSCompoundOperationErrorDomain
147
                                              code:FIRCLSCompoundOperationErrorCodeCancelled
148
                                          userInfo:@{
149
                                            NSLocalizedDescriptionKey : [NSString
150
                                                stringWithFormat:@"%@ cancelled", self.name]
151
                                          }]];
152
    self.asyncCompletion = nil;
153
  } else if (self.completedOperations + self.errors.count == self.operations.count) {
154
    NSError *error = nil;
155
    if (self.errors.count > 0) {
156
      error = [NSError
157
          errorWithDomain:FIRCLSCompoundOperationErrorDomain
158
                     code:FIRCLSCompoundOperationErrorCodeSuboperationFailed
159
                 userInfo:@{FIRCLSCompoundOperationErrorUserInfoKeyUnderlyingErrors : self.errors}];
160
    }
161
    [self finishWithError:error];
162
  }
163
}
164
 
165
@end