Skip to content

Instantly share code, notes, and snippets.

@ChristianKienle
Last active August 29, 2015 14:07
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChristianKienle/df8b00a6a87494df6367 to your computer and use it in GitHub Desktop.
Save ChristianKienle/df8b00a6a87494df6367 to your computer and use it in GitHub Desktop.
#import <Foundation/Foundation.h>
@class CKRecordID;
@interface CKCPartialErrorItem : NSObject
@property (strong) NSError *error;
@property (strong) CKRecordID *recordID;
@end
@class CKRecord;
@interface NSError (Convenience)
@property (readonly) BOOL isCloudKitError;
#pragma mark - Server Record Change Error
@property (readonly) BOOL isServerRecordChangedError;
@property (readonly) CKRecord *ancestorRecord;
@property (readonly) CKRecord *serverRecord;
@property (readonly) CKRecord *clientRecord;
#pragma mark - Retryable Errors
@property (readonly) BOOL isRequestRateLimitedError;
@property (readonly) BOOL isServiceUnavailableError;
@property (readonly) BOOL isRetryableError;
// returns -1 if there is no retry entry in the user info dictionary of this error
// or if isRequestRateLimitedError is NO.
@property (readonly) NSTimeInterval retryAfterInSeconds;
#pragma mark - Partial Failiure Error
@property (readonly) BOOL isPartialFailureError;
// The user info dictionary of a partial failure error contains a dictionary
// for the 'CKPartialErrorsByItemIDKey'. This dictionary is returned by this property.
@property (readonly) NSDictionary *partialErrorsByItemID;
// A batch request can partially fail. If so there are real errors that describe the
// reason as to why the whole batch request failed. Those erros (+ the record ID)
// is returned by realPartialErrorItems.
@property (readonly) NSSet *realPartialErrorItems; // CKCPartialErrorItem
// If a batch request partially failed then partialErrorsByItemID also contains
// the errors (+ the record ID) for the records that failed because the batch request
// failed as a whole because of the erros that are contained in realPartialErrorItems.
@property (readonly) NSSet *batchRequestPartialErrorItems; // CKCPartialErrorItem
// Indicates an error that was generated because a batch failed as a whole.
@property (readonly) BOOL isBatchRequestFailedError;
// Indicates a real error.
@property (readonly) BOOL isRealPartialError;
#pragma mark - Misc
@property (readonly) BOOL isUnknownItemError;
// Request size too large (too many records in the request - make smaller batches)
@property (readonly) BOOL isLimitExceededError;
@property (readonly) BOOL isQuotaExceededError;
@end
/// IMPLEMENTATION
#import "NSError+Convenience.h"
#import <CloudKit/CloudKit.h>
@implementation CKCPartialErrorItem
- (NSString *)description {
return [NSString stringWithFormat:@"%@ ID: %@ - error: %@", [super description], self.recordID, self.error];
}
@end
@implementation NSError (Convenience)
- (BOOL)isCloudKitError {
return [self.domain isEqualToString:CKErrorDomain];
}
- (BOOL)isCloudKitErrorWithCode:(CKErrorCode)cloudKitCode {
return (self.isCloudKitError && self.code == cloudKitCode);
}
- (BOOL)isServerRecordChangedError {
return [self isCloudKitErrorWithCode:CKErrorServerRecordChanged];
}
- (CKRecord *)ancestorRecord {
return self.userInfo[CKRecordChangedErrorAncestorRecordKey];
}
- (CKRecord *)serverRecord {
return self.userInfo[CKRecordChangedErrorServerRecordKey];
}
- (CKRecord *)clientRecord {
return self.userInfo[CKRecordChangedErrorClientRecordKey];
}
#pragma mark - Retryable Errors
- (BOOL)isRequestRateLimitedError {
return [self isCloudKitErrorWithCode:CKErrorRequestRateLimited];
}
- (BOOL)isServiceUnavailableError {
return [self isCloudKitErrorWithCode:CKErrorServiceUnavailable];
}
- (BOOL)isRetryableError {
return (self.isRequestRateLimitedError || self.isServiceUnavailableError);
}
- (NSTimeInterval)retryAfterInSeconds {
if(self.isRequestRateLimitedError == NO) {
return -1.0;
}
NSNumber *retryAfter = self.userInfo[CKErrorRetryAfterKey];
if(retryAfter == nil) {
return -1.0;
}
return retryAfter.doubleValue;
}
#pragma mark - Partial Failiure Error
- (BOOL)isPartialFailureError {
return [self isCloudKitErrorWithCode:CKErrorPartialFailure];
}
- (NSDictionary *)partialErrorsByItemID {
return self.userInfo[CKPartialErrorsByItemIDKey];
}
- (NSSet *)realPartialErrorItems {
NSDictionary *partialErrorsByItemID = self.partialErrorsByItemID;
NSMutableSet *errorItems = [NSMutableSet new];
for(CKRecordID *recordID in partialErrorsByItemID) {
NSError *error = partialErrorsByItemID[recordID];
if(error.isRealPartialError) {
CKCPartialErrorItem *item = [CKCPartialErrorItem new];
item.error = error;
item.recordID = recordID;
[errorItems addObject:item];
}
}
return errorItems;
}
- (NSSet *)batchRequestPartialErrorItems {
NSDictionary *partialErrorsByItemID = self.partialErrorsByItemID;
NSMutableSet *errorItems = [NSMutableSet new];
for(CKRecordID *recordID in partialErrorsByItemID) {
NSError *error = partialErrorsByItemID[recordID];
if(error.isBatchRequestFailedError) {
CKCPartialErrorItem *item = [CKCPartialErrorItem new];
item.error = error;
item.recordID = recordID;
[errorItems addObject:item];
}
}
return errorItems;
}
- (BOOL)isBatchRequestFailedError {
return [self isCloudKitErrorWithCode:CKErrorBatchRequestFailed];
}
- (BOOL)isRealPartialError {
return !self.isBatchRequestFailedError;
}
#pragma mark - Misc
- (BOOL)isUnknownItemError {
return [self isCloudKitErrorWithCode:CKErrorUnknownItem];
}
- (BOOL)isLimitExceededError {
return [self isCloudKitErrorWithCode:CKErrorLimitExceeded];
}
- (BOOL)isQuotaExceededError {
return [self isCloudKitErrorWithCode:CKErrorQuotaExceeded];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment