苹果的示例项目CloudKitShare at 与其他CloudKit用户共享iCloud数据有一行代码,检查符合传递给处理CloudKit错误的函数的错误协议的参数“Error”是否可以在函数开始时转换为NSError,如果不是,则返回零。
下面是在函数开始时进行检查的代码:
guard let nsError = error as NSError? else {
return nil
}函数的返回值是'CKError?‘。
这种检查的目的是什么?函数声明上方的注释说:
//返回零:没有错误或者错误是可忽略的。
我该如何检查这个案子失败的原因?当我将' Error‘参数打印到调试窗口时,似乎总是打印参数是错误类型的可选参数。
代码:
print(type(of: error))调试窗口:
Optional<Error>以下是相关代码。我缩小了函数返回零的所有可能原因:
以下是所有相关代码:
// Return nil: No error or the error is ignorable.
// Return a CKError: There's an error. The caller needs to determine how to handle it.
//
func handleCloudKitError(_ error: Error?, operation: CloudKitOperationType,
affectedObjects: [Any]? = nil, alert: Bool = false) -> CKError? {
// nsError == nil: Everything goes well and the caller can continue.
//
guard let nsError = error as NSError? else {
return nil
}
// Partial errors can happen when fetching or changing the database.
//
// When modifying zones, records, and subscriptions, .serverRecordChanged may happen if
// the other peer changes the item at the same time. In that case, retrieve the first
// CKError object and return to the caller.
//
// In the case of .fetchRecords and fetchChanges, the other peer might delete the specified
// items or zones, so they might not exist in the database (.unknownItem or .zoneNotFound).
//
if let partialError = nsError.userInfo[CKPartialErrorsByItemIDKey] as? NSDictionary {
// If the error doesn't affect the affectedObjects, ignore it.
// If it does, only handle the first error.
//
let errors = affectedObjects?.map({ partialError[$0] }).filter({ $0 != nil })
guard let ckError = errors?.first as? CKError else {
return nil
}
return handlePartialError(ckError, operation: operation, alert: alert)
}
// In the case of fetching changes:
// .changeTokenExpired: Return for callers to refetch with a nil server token.
// .zoneNotFound: Return for callers to switch zones because the current zone doesn't exist.
// .partialFailure: zoneNotFound triggers a partial error as well.
//
if operation == .fetchChanges {
if let ckError = error as? CKError {
if ckError.code == .changeTokenExpired || ckError.code == .zoneNotFound {
return ckError
}
}
}
// If the client requires an alert, alert the error, or append the error message to an existing alert.
//
if alert {
alertError(code: nsError.code, domain: nsError.domain,
message: nsError.localizedDescription, operation: operation)
}
print("\(operation.rawValue) operation error: \(nsError)")
return error as? CKError
}
private func handlePartialError(_ error: CKError, operation: CloudKitOperationType,
alert: Bool = false) -> CKError? {
// Items don't exist. Silently ignore the error for the .delete... operation.
//
if operation == .deleteZones || operation == .deleteRecords || operation == .deleteSubscriptions {
if error.code == .unknownItem {
return nil
}
}
if error.code == .serverRecordChanged {
print("Server record changed. Consider using serverRecord and ignore this error!")
} else if error.code == .zoneNotFound {
print("Zone not found. May have been deleted. Probably ignore!")
} else if error.code == .unknownItem {
print("Unknown item. May have been deleted. Probably ignore!")
} else if error.code == .batchRequestFailed {
print("Atomic failure!")
} else {
if alert {
alertError(code: error.errorCode, domain: CKError.errorDomain,
message: error.localizedDescription, operation: operation)
}
print("\(operation.rawValue) operation error: \(error)")
}
return error
}
private func alertError(code: Int, domain: String, message: String, operation: CloudKitOperationType) {
print("#", #function)
DispatchQueue.main.async {
guard let scene = UIApplication.shared.connectedScenes.first,
let sceneDeleate = scene.delegate as? SceneDelegate,
let viewController = sceneDeleate.window?.rootViewController else {
return
}
let message = "\(operation.rawValue) operation hit error.\n" +
"Error code: \(code)\n" + "Domain: \(domain)\n" + message
if let existingAlert = viewController.presentedViewController as? UIAlertController {
print("message:", existingAlert.message)
existingAlert.message = (existingAlert.message ?? "") + "\n\n\(message)"
return
}
let newAlert = UIAlertController(title: "CloudKit Operation Error!",
message: message, preferredStyle: .alert)
newAlert.addAction(UIAlertAction(title: "OK", style: .default))
print("message:", message)
viewController.present(newAlert, animated: true)
}
}发布于 2022-07-30 03:33:29
简短回答
是的,可能需要转换为NSError一致性。NSError具有Swift Error没有的属性。如果您正在使用旧的代码库,或者您想要一个NSError提供什么,您可能会不时地与它们打交道。
长答案
我觉得文档中的例子有点误导。将错误转换为NSError?是completionHandler回调的一个参数,我们对此一无所知。我的假设是,这个文档要么是旧的,要么是面向那些处理旧代码库的人。如果你是斯威夫特的新手,而且你没有处理这类事情,我可以看出这是多么令人困惑。
为了完成,假设您正在使用一个5年前构建的第三方库。他们的框架中可能会有大量的NSErrors。大多数Swift接口都需要处理Error协议,但是如果您想要NSError对象的任何特殊细节,首先需要将错误转换为NSError (如果可能的话)。
https://stackoverflow.com/questions/73172623
复制相似问题