在 Swift 中,对于 AnyObject,我如何 setValue() 然后调用 valueForKey()

Posted

技术标签:

【中文标题】在 Swift 中,对于 AnyObject,我如何 setValue() 然后调用 valueForKey()【英文标题】:In Swift, for AnyObject, how do I setValue() then call valueForKey() 【发布时间】:2014-10-31 04:06:36 【问题描述】:

我想在 AnyObject 中存储一个值,然后按如下方式检索它:

var obj:AnyObject = UIButton()
obj.setValue("James", forKey: "owner")
obj.valueForKey("owner")

但是,AnyObject 不允许这样做,即使这些方法可用,如错误所示:

setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key owner.'

这是怎么做到的?

【问题讨论】:

UIButton 和 AnyObject 都没有 owner 属性,所以你在这里期待什么? @matt,“所有者”只是任何用户定义的密钥。主要问题是如何使用 AnyObject 可用(编译)的 .setValue 和 .valueForKey 方法? 你使用它们就好了。这就是您的应用程序编译的原因。但是当你的应用程序运行时,就会发现没有这样的密钥。正如我在下面的回答中所说,UIButton 或 AnyObject 没有“用户定义的键”。 【参考方案1】:

您不能分配给 UIButton 的任意键。有些类确实允许这样做(想到 CALayer 和 CAAnimation,当然还有 NSDictionary),但 UIButton 和 AnyObject 都不是这样的类,也没有owner 属性——所以试图设置它是无稽之谈,这就是导致运行时崩溃。您可以使用键设置按钮的 现有 属性,但不能像这样发明自己的键。

【讨论】:

在 Swift 中容易获得运行时对象关联吗? @Tommy 不。在大多数语言中,它们很难获得,因为对象的内存布局是固定的。但是很少需要该功能,因为它需要动态访问属性(使用其名称)并且有更简单的方法可以实现相同的功能,例如封装、继承或单独的字典。 Swift 不是 javascript @Tommy 你真的想要做什么?可能有一种更简单的方法...在我看来,您问错了问题 - 您已经假设一种实现目标的方法,而不是询问如何完成这个目标。 不是我的问题;我真正想要做的只是借此机会了解 Swift 对另一个 Objective-C 运行时特性的访问(如果有的话)。我还没有太多机会使用 Swift。 抱歉,我搞不清楚谁是谁了。【参考方案2】:

您不能只为对象动态添加属性。这不是 Swift 的工作方式。你可以在 Javascript 中摆脱它(在 Obj-C 中也有一点),但在 Swift 中却不行。

有几种简单的方法可以解决您的问题:

    封装 - 创建一个封装按钮及其所有者的类,例如OwnedButton。 继承 - 覆盖 UIButton,为其添加一个新的 owner 属性。然后你就可以设置button.owner = ...。 让所有者保存它拥有的按钮owner.addButton(button) 单独保存关系,例如使用按钮所有者字典。

【讨论】:

【参考方案3】:

关于按钮,您可以创建可存储的对象数组。请参阅下面的 NSCoding 用法。

我定义对象的类 - 我编写的游戏示例:

import Foundation

class ButtonStates: NSObject 

    var sign: String = "+"
    var level: Int = 1
    var problems: Int = 10
    var time: Int = 30
    var skipWrongAnswers = true

    func encodeWithCoder(aCoder: NSCoder!) 
        aCoder.encodeObject(sign, forKey: "sign")
        aCoder.encodeInteger(level, forKey: "level")
        aCoder.encodeInteger(problems, forKey: "problems")
        aCoder.encodeInteger(time, forKey: "time")
        aCoder.encodeBool(skipWrongAnswers, forKey: "skipWrongAnswers")
    

    init(coder aDecoder: NSCoder!) 
        sign = aDecoder.decodeObjectForKey("sign") as String
        level = aDecoder.decodeIntegerForKey("level")
        problems = aDecoder.decodeIntegerForKey("problems")
        time = aDecoder.decodeIntegerForKey("time")
        skipWrongAnswers = aDecoder.decodeBoolForKey("skipWrongAnswers")
    

    override init() 
    

我归档和检索这些对象的类:

import Foundation

class ArchiveButtonStates:NSObject 

    var documentDirectories:NSArray = []
    var documentDirectory:String = ""
    var path:String = ""

    func ArchiveButtons(#buttonStates: ButtonStates) 
        documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        documentDirectory = documentDirectories.objectAtIndex(0) as String
        path = documentDirectory.stringByAppendingPathComponent("buttonStates.archive")

        if NSKeyedArchiver.archiveRootObject(buttonStates, toFile: path) 
            //println("Success writing to file!")
         else 
            println("Unable to write to file!")
        
    

    func RetrieveButtons() -> NSObject 
        var dataToRetrieve = ButtonStates()
        documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        documentDirectory = documentDirectories.objectAtIndex(0) as String
        path = documentDirectory.stringByAppendingPathComponent("buttonStates.archive")
        if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? ButtonStates 
            dataToRetrieve = dataToRetrieve2 as ButtonStates
        
        return(dataToRetrieve)
    

从 ViewController 检索数据的示例:

let buttonStates = ArchiveButtonStates().RetrieveButtons() as ButtonStates

从 ViewController 存储数据的示例:

ArchiveGameData().ArchiveResults(dataSet: gameDataArray)

【讨论】:

【参考方案4】:

UIButton-[NSObject setValue:forKey:]-[NSObject valueForKey:] 是 Objective-C Cocoa API。所以你的代码不能工作的原因与相应的 Objective-C 代码不能工作的原因完全相同:

id obj = [[UIButton alloc] init];
[obj setValue:@"James" forKey:@"owner"];
[obj valueForKey:@"owner"];

一旦你弄清楚了,你就会发现你的代码存在问题。

【讨论】:

以上是关于在 Swift 中,对于 AnyObject,我如何 setValue() 然后调用 valueForKey()的主要内容,如果未能解决你的问题,请参考以下文章

类型'(String,AnyObject)'在swift中没有下标成员

在 Swift 中使用 JSON 的 Alamofire 请求后,如何在 AnyObject 中转换 <AnyObject> 响应?

如何在 swift 中使用 AnyObject 将结构转换为对象

Swift 中的 AnyObject 和 Any

在 Swift 中:Array VS NSArray VS [AnyObject] 之间的区别

如何在 Swift 中将键值对添加到类型为 [String:AnyObject] 的字典中?