在 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 将结构转换为对象