mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-10 23:33:29 +01:00
129 lines
5.1 KiB
Swift
129 lines
5.1 KiB
Swift
//
|
|
// NSError+AltStore.swift
|
|
// AltStore
|
|
//
|
|
// Created by Riley Testut on 3/11/20.
|
|
// Copyright © 2020 Riley Testut. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
extension NSError {
|
|
@objc(alt_localizedFailure)
|
|
var localizedFailure: String? {
|
|
let localizedFailure = (userInfo[NSLocalizedFailureErrorKey] as? String) ?? (NSError.userInfoValueProvider(forDomain: domain)?(self, NSLocalizedFailureErrorKey) as? String)
|
|
return localizedFailure
|
|
}
|
|
|
|
@objc(alt_localizedDebugDescription)
|
|
var localizedDebugDescription: String? {
|
|
let debugDescription = (userInfo[NSDebugDescriptionErrorKey] as? String) ?? (NSError.userInfoValueProvider(forDomain: domain)?(self, NSDebugDescriptionErrorKey) as? String)
|
|
return debugDescription
|
|
}
|
|
|
|
@objc(alt_errorWithLocalizedFailure:)
|
|
func withLocalizedFailure(_ failure: String) -> NSError {
|
|
var userInfo = self.userInfo
|
|
userInfo[NSLocalizedFailureErrorKey] = failure
|
|
|
|
if let failureReason = localizedFailureReason {
|
|
userInfo[NSLocalizedFailureReasonErrorKey] = failureReason
|
|
} else if localizedFailure == nil && localizedFailureReason == nil && localizedDescription.contains(localizedErrorCode) {
|
|
// Default localizedDescription, so replace with just the localized error code portion.
|
|
userInfo[NSLocalizedFailureReasonErrorKey] = "(\(localizedErrorCode).)"
|
|
} else {
|
|
userInfo[NSLocalizedFailureReasonErrorKey] = localizedDescription
|
|
}
|
|
|
|
if let localizedDescription = NSError.userInfoValueProvider(forDomain: domain)?(self, NSLocalizedDescriptionKey) as? String {
|
|
userInfo[NSLocalizedDescriptionKey] = localizedDescription
|
|
}
|
|
|
|
// Don't accidentally remove localizedDescription from dictionary
|
|
// userInfo[NSLocalizedDescriptionKey] = NSError.userInfoValueProvider(forDomain: self.domain)?(self, NSLocalizedDescriptionKey) as? String
|
|
|
|
if let recoverySuggestion = localizedRecoverySuggestion {
|
|
userInfo[NSLocalizedRecoverySuggestionErrorKey] = recoverySuggestion
|
|
}
|
|
|
|
let error = NSError(domain: domain, code: code, userInfo: userInfo)
|
|
return error
|
|
}
|
|
|
|
func sanitizedForCoreData() -> NSError {
|
|
var userInfo = self.userInfo
|
|
userInfo[NSLocalizedFailureErrorKey] = localizedFailure
|
|
userInfo[NSLocalizedDescriptionKey] = localizedDescription
|
|
userInfo[NSLocalizedFailureReasonErrorKey] = localizedFailureReason
|
|
userInfo[NSLocalizedRecoverySuggestionErrorKey] = localizedRecoverySuggestion
|
|
|
|
// Remove userInfo values that don't conform to NSSecureEncoding.
|
|
userInfo = userInfo.filter { _, value in
|
|
(value as AnyObject) is NSSecureCoding
|
|
}
|
|
|
|
// Sanitize underlying errors.
|
|
if let underlyingError = userInfo[NSUnderlyingErrorKey] as? Error {
|
|
let sanitizedError = (underlyingError as NSError).sanitizedForCoreData()
|
|
userInfo[NSUnderlyingErrorKey] = sanitizedError
|
|
}
|
|
|
|
if #available(iOS 14.5, macOS 11.3, *), let underlyingErrors = userInfo[NSMultipleUnderlyingErrorsKey] as? [Error] {
|
|
let sanitizedErrors = underlyingErrors.map { ($0 as NSError).sanitizedForCoreData() }
|
|
userInfo[NSMultipleUnderlyingErrorsKey] = sanitizedErrors
|
|
}
|
|
|
|
let error = NSError(domain: domain, code: code, userInfo: userInfo)
|
|
return error
|
|
}
|
|
}
|
|
|
|
extension Error {
|
|
var underlyingError: Error? {
|
|
let underlyingError = (self as NSError).userInfo[NSUnderlyingErrorKey] as? Error
|
|
return underlyingError
|
|
}
|
|
|
|
var localizedErrorCode: String {
|
|
let localizedErrorCode = String(format: NSLocalizedString("%@ error %@", comment: ""), (self as NSError).domain, (self as NSError).code as NSNumber)
|
|
return localizedErrorCode
|
|
}
|
|
}
|
|
|
|
protocol ALTLocalizedError: LocalizedError, CustomNSError {
|
|
var failure: String? { get }
|
|
|
|
var underlyingError: Error? { get }
|
|
}
|
|
|
|
extension ALTLocalizedError {
|
|
var errorUserInfo: [String: Any] {
|
|
let userInfo = ([
|
|
NSLocalizedDescriptionKey: errorDescription,
|
|
NSLocalizedFailureReasonErrorKey: failureReason,
|
|
NSLocalizedFailureErrorKey: failure,
|
|
NSUnderlyingErrorKey: underlyingError
|
|
] as [String: Any?]).compactMapValues { $0 }
|
|
return userInfo
|
|
}
|
|
|
|
var underlyingError: Error? {
|
|
// Error's default implementation calls errorUserInfo,
|
|
// but ALTLocalizedError.errorUserInfo calls underlyingError.
|
|
// Return nil to prevent infinite recursion.
|
|
nil
|
|
}
|
|
|
|
var errorDescription: String? {
|
|
guard let errorFailure = failure else { return (underlyingError as NSError?)?.localizedDescription }
|
|
guard let failureReason = failureReason else { return errorFailure }
|
|
|
|
let errorDescription = errorFailure + " " + failureReason
|
|
return errorDescription
|
|
}
|
|
|
|
var failureReason: String? { (underlyingError as NSError?)?.localizedDescription }
|
|
var recoverySuggestion: String? { (underlyingError as NSError?)?.localizedRecoverySuggestion }
|
|
var helpAnchor: String? { (underlyingError as NSError?)?.helpAnchor }
|
|
}
|