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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26667380/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 06:03:36  来源:igfitidea点击:

In Swift, for AnyObject, how do I setValue() then call valueForKey()

iosxcodeswift

提问by yjsa

I'd like to store a value in AnyObject then retrieve it later as follows:

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

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

However, AnyObject does not allow it even if these methods are available as shown by the error:

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

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

How could this be done?

这怎么可能?

回答by matt

You cannot assign to an arbitrary key of a UIButton. Some classes do permit this (CALayer and CAAnimation come to mind, and NSDictionary of course), but neither UIButton nor AnyObject is such a class, and neither has an ownerproperty — so trying to set it is nonsense, and that is what causes the crash at runtime. You can set a button's existingproperty using a key, but you can't just invent your own key like this.

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

回答by Sulthan

You cannot just add properties to objects dynamically. That's not how Swift works. You could get away with it in Javascript (and a bit in Obj-C) but not in Swift.

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

There are several simple ways out of your problem:

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

  1. Encapsulation - create a class encapsulating a button and its owner, e.g. OwnedButton.
  2. Inheritance - Override UIButton, adding it a new ownerproperty. Then you will be able to just set button.owner = ....
  3. Let the owner save the buttons it owns owner.addButton(button)
  4. Save the relation separately, e.g. using a button-owner dictionary.
  1. 封装 - 创建一个封装按钮及其所有者的类,例如OwnedButton.
  2. 继承 - 覆盖 UIButton,为它添加一个新owner属性。然后你就可以设置了button.owner = ...
  3. 让所有者保存其拥有的按钮 owner.addButton(button)
  4. 单独保存关系,例如使用按钮所有者字典。

回答by Steve Rosenberg

Regarding your buttons, you can create array of objects that can be stored. See use of NSCoding below.

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

Class where I define objects - example from a game I wrote:

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

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() {
    }
}

Class where I archive and retrieve these objects:

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

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)
    }
}

example of retrieving the data from a ViewController:

从 ViewController 检索数据的示例:

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

example of storing data from a ViewController:

从 ViewController 存储数据的示例:

ArchiveGameData().ArchiveResults(dataSet: gameDataArray)

回答by newacct

UIButton, -[NSObject setValue:forKey:]and -[NSObject valueForKey:]are Objective-C Cocoa APIs. So your code does not work for the exact same reason that the corresponding Objective-C code does not work:

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

Once you figure that out, you will have figured out the problem with your code.

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