如何在Swfit 4.0中使用键值编码?

时间:2017-12-07 09:25:32

标签: ios swift xcode9 kvc

我之前从未使用过Swift4,也不知道如何在其中使用KVC 我尝试使用Dictionary创建模型,这里是代码:

class Person : NSObject {
    var name: String = ""
    var age: Int = 0

    init(dict: [String : Any]) {
        super.init()
        self.setValuesForKeys(dict)
    }
}

let dict: [String : Any] = ["name" : "Leon", "age" : 18]
let p = Person(dict: dict)
print(p.name, p.age)

我有两个问题:
1.为什么我不使用AnyObject"Leon"18推断为StringInt,它是否在KVC中使用?
2. @objc var name: String = "",这种形式有效,但我无法理解
谢谢你的帮助。

4 个答案:

答案 0 :(得分:13)

要在Swift 4中为属性实现KVC支持,您需要做两件事:

  1. 由于KVC的当前实现是用Objective-C编写的,因此您需要在属性上使用@objc注释,以便Objective-C可以看到它。这也意味着属性的类型需要与Objective-C兼容。

  2. 除了将属性公开给Objective-C之外,您还需要设置通知,以便在属性更改时通知观察者。有三种方法可以做到这一点:

  3. 对于存储的属性,最简单的方法是添加dynamic关键字,如下所示:

    @objc dynamic var foo: String
    

    这将允许Cocoa使用Objective-C魔法为您自动生成所需的通知,通常是您想要的。但是,如果您需要更好的控制,您也可以手动编写通知代码:

    @objc private static let automaticallyNotifiesObserversOfFoo = false
    @objc var foo: String {
        willSet { self.willChangeValue(for: \.foo) }
        didSet { self.didChangeValue(for: \.foo) }
    }
    

    automaticallyNotifiesObserversOf<property name>属性是指向KVC / KVO系统表明我们自己正在处理通知,并且Cocoa不应该尝试为我们生成通知。

    最后,如果你的财产没有存储,而是依赖于其他一些属性或属性,你需要实现keyPathsForValuesAffecting<your property name here>方法,如下所示:

    @objc dynamic var foo: Int
    @objc dynamic var bar: Int
    
    @objc private static let keyPathsForValuesAffectingBaz: Set<String> = [
        #keyPath(foo), #keyPath(bar)
    ]
    @objc var baz: Int { return self.foo + self.bar }
    

    在上面的示例中,当baz的值或foo的值发生变化时,系统会通知bar属性的观察者。

答案 1 :(得分:1)

  1. 在swift中,所有类继承NSObject都符合KVC,类型不是实例,Any代表类型,AnyObject例如

  2. @objc用于Objective-c类调用它。

  3. 键路径表达式接受属性引用和链式属性引用,例如\ Animal.name.count

    class Animal: NSObject {
        @objc var name: String
    
        init(name: String) {
            self.name = name
        }
    }
    
    let llama = Animal(name: "Llama")
    let nameAccessor = \Animal.name
    let nameCountAccessor = \Animal.name.count
    llama[keyPath: nameAccessor]
    // "Llama"
    llama[keyPath: nameCountAccessor]
    // "5"
    

    Using Swift with Cocoa and Objective-C有详细信息

答案 2 :(得分:0)

  1. 您的代码

    var name: String = "" var age: Int = 0

    当您确定其类型时,您可以编写相同的代码。

    var name = "" var age = 0

    Any通常用于所有类型(函数类型和可选类型),而AnyObject用于Class类型。

  2. @objc有不同的含义,当你在swift类中使用@objc时,该代码在objective-c中可用。您应该使用@objc属性指定与objective-c类相同,结果旧的档案可以被新的swift类替换。

答案 3 :(得分:0)

一切都适合我,但仍然出现此错误,然后我通过以下方式解决了

  • 在身份检查器中启用“ 从目标继承模块”。 或
  • 从“身份检查器”的“自定义类”中提供存在该模块的模块(通常是文件夹名称/组名称)