Ios 在Swift中,对于任何对象,如何设置value(),然后调用valueForKey()

Ios 在Swift中,对于任何对象,如何设置value(),然后调用valueForKey(),ios,xcode,swift,Ios,Xcode,Swift,我想在任何对象中存储一个值,然后按如下方式检索它: 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.'

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

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分配任意键。有些类确实允许这样做(我想到的是CALayer和CAAnimation,当然还有NSDictionary),但UIButton和AnyObject都不是这样的类,而且都没有
owner
属性-因此试图设置它是毫无意义的,这就是运行时崩溃的原因。可以使用键设置按钮的现有属性,但不能像这样发明自己的键。

关于按钮,可以创建可存储的对象数组。请参见下面的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
ArchiveGameData().ArchiveResults(dataSet: gameDataArray)
存储来自ViewController的数据的示例:

let buttonStates = ArchiveButtonStates().RetrieveButtons() as ButtonStates
ArchiveGameData().ArchiveResults(dataSet: gameDataArray)

您不能只是动态地向对象添加属性。斯威夫特不是这样工作的。你可以用Javascript(还有一点Obj-C)但不能用Swift

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

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

  • ui按钮
    -[NSObject setValue:forKey:][/code>和
    -[NSObject valueForKey:][/code>都是Objective-C Cocoa API。因此,您的代码不工作的原因与相应的Objective-C代码不工作的原因完全相同:

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

    一旦你明白了这一点,你就会明白代码的问题。

    UIButton和AnyObject都没有属性
    所有者,那么你在这里期待什么呢?@matt,“所有者”只是任何用户定义的键。主要问题是如何使用可用于任何对象(编译)的.setValue和.valueForKey方法?您使用它们很好。这就是你的应用程序编译的原因。但当你的应用程序运行时,结果是没有这样的密钥。正如我在下面的回答中所说,UIButton或AnyObject没有“用户定义键”。运行时对象关联是否容易从Swift获得?@Tommy否。在大多数语言中,它们很难获得,因为对象的内存布局是固定的。但是很少需要该功能,因为它需要动态访问属性(使用其名称),并且有更简单的方法来实现相同的功能,例如封装、继承或单独的字典。斯威夫特不是,汤米,你真正想做的是什么?也许有一个更简单的方法。。。在我看来,你提出了一个错误的问题——你假设了一种实现目标的方式,而不是问如何实现这个目标;我真正想做的就是借此机会了解Swift对Objective-C运行时特性的访问(如果有的话)。我还没有太多机会使用Swift。对不起,我不知道谁是谁。