首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在iOS应用程序中是否需要检查符合错误协议的变量是否转换为NSError?

在iOS应用程序中是否需要检查符合错误协议的变量是否转换为NSError?
EN

Stack Overflow用户
提问于 2022-07-30 03:18:17
回答 1查看 49关注 0票数 0

苹果的示例项目CloudKitShare at 与其他CloudKit用户共享iCloud数据有一行代码,检查符合传递给处理CloudKit错误的函数的错误协议的参数“Error”是否可以在函数开始时转换为NSError,如果不是,则返回零。

下面是在函数开始时进行检查的代码:

代码语言:javascript
复制
guard let nsError = error as NSError? else {
    return nil
}

函数的返回值是'CKError?‘。

这种检查的目的是什么?函数声明上方的注释说:

//返回零:没有错误或者错误是可忽略的。

我该如何检查这个案子失败的原因?当我将' Error‘参数打印到调试窗口时,似乎总是打印参数是错误类型的可选参数。

代码:

代码语言:javascript
复制
print(type(of: error))

调试窗口:

代码语言:javascript
复制
Optional<Error>

以下是相关代码。我缩小了函数返回零的所有可能原因:

  1. 将“Error”作为类型错误的参数不能转换为NSError,这正是这个问题的要点。
  2. NSError.userInfo不保存CKPartialErrorsByItemIDKey键的值,也不将值转换为NSDictionary。
  3. affectedObjects参数不传递值。
  4. affectedObjects参数和CKPartialErrorsByItemIDKey键的值不包含转换为CKError的任何共同项。
  5. “操作”的参数不等于在“handlePartialError(_:operation:alert)”中选中的任何值,即.deleteZones、.deleteRecords或.deleteSubscriptions。
  6. 类型为enumCKError.Code的CKError.code的值等于.unknownItem,苹果文档表示,这意味着“指定的记录不存在”。
  7. 以下不正确:操作参数等于.fetchChanges,而CKError.code等于.changeTokenExpired或.zoneNotFound。
  8. 在将参数'error‘转换为CKError之后,它不会被转换为NSError。

以下是所有相关代码:

代码语言:javascript
复制
// 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)
    }
}
EN

回答 1

Stack Overflow用户

发布于 2022-07-30 03:33:29

简短回答

是的,可能需要转换为NSError一致性。NSError具有Swift Error没有的属性。如果您正在使用旧的代码库,或者您想要一个NSError提供什么,您可能会不时地与它们打交道。

长答案

我觉得文档中的例子有点误导。将错误转换为NSError?completionHandler回调的一个参数,我们对此一无所知。我的假设是,这个文档要么是旧的,要么是面向那些处理旧代码库的人。如果你是斯威夫特的新手,而且你没有处理这类事情,我可以看出这是多么令人困惑。

为了完成,假设您正在使用一个5年前构建的第三方库。他们的框架中可能会有大量的NSErrors。大多数Swift接口都需要处理Error协议,但是如果您想要NSError对象的任何特殊细节,首先需要将错误转换为NSError (如果可能的话)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73172623

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档