NSTimer
을 사용하는 대신 dispatch_after
을 사용하십시오.
print("Network failure!!")
if let retryAfterValue = error.userInfo[CKErrorRetryAfterKey] as? NSTimeInterval {
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(retryAfterValue * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
saveHandler(saveRecord: saveRecord, error: error)
}
}
여기는 모든 레코드 수정 및 삭제에 사용되는 도우미 메서드 (Objective-C)입니다. 일반적인 오류 및 재 시도를 처리합니다.
- (void)modifyRecords:(NSArray<CKRecord *> *)records andDeleteRecords:(NSArray<CKRecordID *> *)deleteIds completion:(void (^)(NSArray<CKRecord *> *savedRecords, NSArray<CKRecordID *> *deletedRecordIDs, NSError *error))completion {
CKModifyRecordsOperation *op = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:records recordIDsToDelete:deleteIds];
op.savePolicy = CKRecordSaveAllKeys;
op.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *operationError) {
NSError *returnError = operationError;
if (operationError) {
switch (operationError.code) {
case CKErrorRequestRateLimited:
case CKErrorServiceUnavailable:
case CKErrorZoneBusy:
{
double delay = 3.0;
NSNumber *delayVal = operationError.userInfo[CKErrorRetryAfterKey];
if (delayVal) {
delay = delayVal.doubleValue;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self modifyRecords:records andDeleteRecords:deleteIds completion:completion];
});
}
return;
case CKErrorPartialFailure:
{
if (savedRecords.count || deletedRecordIDs.count) {
returnError = nil;
}
break;
}
default:
{
NSLog(@"Unhandled error in modify/deleteRecords: %@", operationError);
}
break;
}
}
if (completion) {
completion(savedRecords, deletedRecordIDs, returnError);
}
};
[someCloudKitDatabase addOperation:op];
}
만/추가 기록을 수정 deleteIds
매개 변수에 nil
를 전달하려는 경우
.
스위프트 3의 도우미 메소드가 동일합니다 (테스트되지 않았지만 마지막 행을 제외하고 컴파일됩니다).
func modifyRecords(_ records: [CKRecord]?, andDelete deleteIds: [CKRecordID]?, completionHandler: @escaping ([CKRecord]?, [CKRecordID]?, Error?) -> Void) {
let op = CKModifyRecordsOperation(recordsToSave: records, recordIDsToDelete: deleteIds)
op.savePolicy = .allKeys
op.modifyRecordsCompletionBlock = { (_ savedRecords: [CKRecord]?, _ deletedRecordIds: [CKRecordID]?, _ operationError: Error?) -> Void in
var returnError = operationError
if let ckerror = operationError as? CKError {
switch ckerror {
case CKError.requestRateLimited, CKError.serviceUnavailable, CKError.zoneBusy:
let retry = ckerror.retryAfterSeconds ?? 3.0
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + retry, execute: {
modifyRecords(records, andDelete: deleteIds, completionHandler: completionHandler)
})
return
case CKError.partialFailure:
if (savedRecords != nil && savedRecords!.count > 0) || (deletedRecordIds != nil && deletedRecordIds!.count > 0) {
returnError = nil
}
default:
break
}
}
completionHandler(savedRecords, deletedRecordIds, returnError)
}
someCloudKitDatabase.add(op)
}
Dispatch_after 팁 주셔서 감사합니다. 내 문제는 saveRecord는 실패하는 동안 nil입니다. 코드를 실행하고 wifi를 끄면 오류 코드가 생성됩니다. 그게 내 문제 야. – Coder1224
나는'CKDatabase'의 기본적인'saveRecord' 메쏘드 대신'CKModifyRecordsOperation'을 사용할 것입니다. 당신은 훨씬 더 많은 통제권을 가지며이 "재시도"논리를 사용하는 것이 훨씬 더 간단합니다. – rmaddy
당신은'CKModifyRecordsOperation'가 재시도 로직을 더 단순하게 만드는 예제를 지적 할 수 있습니까? – Coder1224