iOS 如何让一个函数接受确认到 NSCoding 的参数
iOS How to make a function to accept parameter confirming to NSCoding
我有一个函数可以将确认 NSCoding
的基元和对象保存到 UserDefaults
。
func set(_ value: Any?, forKey key: String) {
if let value = value {
if (value is NSCoding) {
let encodedValue = NSKeyedArchiver.archivedData(withRootObject: value)
UserDefaults.standard.set(encodedValue, forKey: key)
} else {
print("Storage: failed to save value for key \(key). Value must confirm to NSCoding protocol")
}
} else {
UserDefaults.standard.removeObject(forKey: key)
}
}
我想去掉函数内部的一致性检查。所以函数必须只接受 NSCoding
个值。
我尝试将函数的签名更改为:
func set(_ value: NSCoding?, forKey key: String)
还有这个:
func set<T: Any>(_ value: T?, forKey key: String) where T: NSCoding
但是,我在每次函数调用中都会遇到编译错误。
在第一种情况下我得到:
Argument type ‘***’ does not conform to expected type 'NSCoding?'
第二个:
Cannot convert value of type '***' to expected argument type '_?'
我应该更改什么才能使其正常工作?
方法声明本身似乎没有问题
func set<T: Any>(_ value: T?, forKey key: String) where T: NSCoding {
if let value = value {
let encodedValue = NSKeyedArchiver.archivedData(withRootObject: value)
UserDefaults.standard.set(encodedValue, forKey: key)
} else {
UserDefaults.standard.removeObject(forKey: key)
}
}
但编译错误指出您传递给此函数的值可能与 NSCoding
不兼容
使用
调用上述函数的示例
self.set("abcd", forKey: "test")
给出错误
Cannot convert value of type 'String' to expected argument type '_?'
另一方面称它为
self.set(NSString(string: "abcd"), forKey: "test")
工作正常。因此,请确保您传递了正确的参数 :)
编辑 1:
根据 OP 的评论,使用 Int
测试了泛型方法
let test: Int = 100
self.set(test, forKey: "test")
导致相同的错误,尽管将其装箱到 NSNumber
let test: Int = 100
self.set(NSNumber(value: test), forKey: "test")
编辑 2:
正在回答 OP 的评论
But why String values pass if (value is NSCoding) check in my original
function?
let a: Any = "abcd"
if a is NSCoding {
debugPrint("am here")
}
那是因为您的 any 通过了 NSCoding
检查,在您的情况下,无论您传递给函数的值是什么,您都将其类型强制转换为 Any
并且 Any
通过了检查: )
因此它在你的第一个方法中工作但失败了泛型:)
希望对你有帮助
也许你可以一起跳过 NSCoding
?
func set(_ value: Any?, forKey key: String) throws {
if let value = value {
let encodedValue = try NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
UserDefaults.standard.set(encodedValue, forKey: key)
} else {
UserDefaults.standard.removeObject(forKey: key)
}
}
(请注意,我更改为未弃用的方法,但您可以随意改回)
例子
do {
try set("abc", forKey: "k1")
} catch {
print(error)
}
我有一个函数可以将确认 NSCoding
的基元和对象保存到 UserDefaults
。
func set(_ value: Any?, forKey key: String) {
if let value = value {
if (value is NSCoding) {
let encodedValue = NSKeyedArchiver.archivedData(withRootObject: value)
UserDefaults.standard.set(encodedValue, forKey: key)
} else {
print("Storage: failed to save value for key \(key). Value must confirm to NSCoding protocol")
}
} else {
UserDefaults.standard.removeObject(forKey: key)
}
}
我想去掉函数内部的一致性检查。所以函数必须只接受 NSCoding
个值。
我尝试将函数的签名更改为:
func set(_ value: NSCoding?, forKey key: String)
还有这个:
func set<T: Any>(_ value: T?, forKey key: String) where T: NSCoding
但是,我在每次函数调用中都会遇到编译错误。
在第一种情况下我得到:
Argument type ‘***’ does not conform to expected type 'NSCoding?'
第二个:
Cannot convert value of type '***' to expected argument type '_?'
我应该更改什么才能使其正常工作?
方法声明本身似乎没有问题
func set<T: Any>(_ value: T?, forKey key: String) where T: NSCoding {
if let value = value {
let encodedValue = NSKeyedArchiver.archivedData(withRootObject: value)
UserDefaults.standard.set(encodedValue, forKey: key)
} else {
UserDefaults.standard.removeObject(forKey: key)
}
}
但编译错误指出您传递给此函数的值可能与 NSCoding
使用
调用上述函数的示例self.set("abcd", forKey: "test")
给出错误
Cannot convert value of type 'String' to expected argument type '_?'
另一方面称它为
self.set(NSString(string: "abcd"), forKey: "test")
工作正常。因此,请确保您传递了正确的参数 :)
编辑 1:
根据 OP 的评论,使用 Int
let test: Int = 100
self.set(test, forKey: "test")
导致相同的错误,尽管将其装箱到 NSNumber
let test: Int = 100
self.set(NSNumber(value: test), forKey: "test")
编辑 2:
正在回答 OP 的评论
But why String values pass if (value is NSCoding) check in my original function?
let a: Any = "abcd"
if a is NSCoding {
debugPrint("am here")
}
那是因为您的 any 通过了 NSCoding
检查,在您的情况下,无论您传递给函数的值是什么,您都将其类型强制转换为 Any
并且 Any
通过了检查: )
因此它在你的第一个方法中工作但失败了泛型:) 希望对你有帮助
也许你可以一起跳过 NSCoding
?
func set(_ value: Any?, forKey key: String) throws {
if let value = value {
let encodedValue = try NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
UserDefaults.standard.set(encodedValue, forKey: key)
} else {
UserDefaults.standard.removeObject(forKey: key)
}
}
(请注意,我更改为未弃用的方法,但您可以随意改回)
例子
do {
try set("abc", forKey: "k1")
} catch {
print(error)
}