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

我想在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的任意键。 有些类允许这样做(CALayer和CAAnimation想起来,NSDictionary当然),但UIButton和AnyObject都不是这样一个类,也没有一个owner属性 – 所以试图设置它是无稽之谈,这是什么原因导致运行时崩溃。 你可以用一个键来设置一个button的现有属性,但是你不能像这样创build自己的键。

你不能dynamic地添加属性到对象。 这不是Swift的工作原理。 你可以用Javascript(和Obj-C中的一些)来避开它,但是不能用在Swift中。

你的问题有几个简单的方法:

  1. 封装 – 创build封装button及其所有者的类,例如OwnedButton
  2. inheritance – 重写UIButton,添加一个新的owner属性。 那么你将能够设置button.owner = ...
  3. 让所有者保存它拥有的buttonowner.addButton(button)
  4. 单独保存关系,例如使用button拥有者字典。

关于你的button,你可以创build可以存储的对象数组。 请参阅下面的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) 

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"]; 

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