在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中。
你的问题有几个简单的方法:
- 封装 – 创build封装button及其所有者的类,例如
OwnedButton
。 - inheritance – 重写UIButton,添加一个新的
owner
属性。 那么你将能够设置button.owner = ...
- 让所有者保存它拥有的button
owner.addButton(button)
- 单独保存关系,例如使用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"];
一旦你弄清楚了,你会发现你的代码存在问题。