iOS如何使函数接受NSCoding的参数确认

时间:2019-02-01 12:19:16

标签: ios swift function swift4 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 

但是,在每个函数调用中都会出现编译错误。

在第一种情况下,我得到:

  

参数类型“ ***”不符合预期的类型“ NSCoding?”

第二个:

  

无法将类型“ ***”的值转换为预期的参数类型“ _?”

我应该进行哪些更改才能使其正常工作?

2 个答案:

答案 0 :(得分:1)

方法声明本身似乎没有问题

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")

出现错误

  

无法将类型为“字符串”的值转换为预期的参数类型为“ _?”

另一方面称它为

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的评论

  

但是如果我的原件(值是NSCoding)签入,为什么要通过字符串值   功能?

    let a: Any = "abcd"
    if a is NSCoding {
        debugPrint("am here")
    }

那是因为你的任何经过NSCoding检查,并在你的情况,无论什么样的价值传递给函数,你键入它转换为AnyAny通过检查:) < / p>

因此可以在您的第一种方法中使用,但无法使用泛型:) 希望对您有帮助

答案 1 :(得分:1)

也许您可以一起跳过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)
}