5

Bonjour,我想将 Aaron 书中的 Objective'c 练习翻译成 swift 但我找不到解决方案。Objective'c 代码是:

@dynamic firstName;
@dynamic lastName;
@dynamic department;

+ (NSSet *)keyPathsForValuesAffectingFullName
{
    return [NSSet setWithObjects:@"firstName", @"lastName", nil];
}

- (NSString *)fullName
{
    NSString *first = [self firstName];
    NSString *last = [self lastName];
    if (!first)
        return last;
    if (!last)
        return first;
    return [NSString stringWithFormat:@"%@ %@", first, last];
}

我在开发人员文档中找到了一个函数,但我不明白如何实现此代码。

更明确地说,这是 Apple 文档

一对一的关系

要为一对一关系自动触发通知,您应该覆盖 keyPathsForValuesAffectingValueForKey: 或实现一个合适的方法,该方法遵循它为注册相关键定义的模式。

例如,一个人的全名取决于名字和姓氏。返回全名的方法可以写成如下:

- (NSString *)fullName {
    return [NSString stringWithFormat:@"%@ %@",firstName, lastName];
}

当 firstName 或 lastName 属性发生更改时,必须通知观察 fullName 属性的应用程序,因为它们会影响属性的值。

一种解决方案是覆盖 keyPathsForValuesAffectingValueForKey:指定一个人的 fullName 属性依赖于 lastName 和 firstName 属性。清单 1 显示了此类依赖项的示例实现:

清单 1 keyPathsForValuesAffectingValueForKey 的示例实现:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {

    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"fullName"]) {
        NSArray *affectingKeys = @[@"lastName", @"firstName"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}

class func keyPathsForValuesAffectingValueForKey(_ key: String) -> NSSet

有人能告诉我如何快速实现这个功能吗?

感谢你们对我的帮助。

4

6 回答 6

5

我找到了我的问题的解决方案!只需用之前的覆盖 func keyPathsForValuesAffectingValueForKey(key: String)

这里的代码:

class Locataires: NSManagedObject {
@NSManaged var firstName: String
@NSManaged var lastName: String
var fullName: NSString {
    get {
 return firstName + lastName
    }
}

override class func keyPathsForValuesAffectingValueForKey(key: String) -> NSSet {
    if key == «fullName « {
        let mesClefs = ["firstName", "lastName"]
        return NSSet(array: mesClefs)
    }
    else {
        return super.keyPathsForValuesAffectingValueForKey(key)
    }
}

感谢一月的帮助

于 2015-02-05T09:57:38.970 回答
2

对于 Swift 4 解决方案是:

@objc dynamic var firstName: String = ""
@objc dynamic var lastName: String = ""
@objc dynamic var fullName: String {
  return "\(firstName) \(lastName)"
}

@objc class func keyPathsForValuesAffectingFullName() -> Set<String> {
  return Set(["firstName", "lastName"])
}
于 2016-04-30T19:18:56.120 回答
1

此解决方案适用于XCode 9+ 和 Swift 4.0(Apple Swift 版本 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38):

@objc public class MyKVOClass : NSObject
{
    // MARK: Properties

    @objc dynamic var myKVOSubclass : KVOSubclass?
    @objc dynamic var myKVOProperty : String?

    @objc dynamic var myComputedKVOProperty : String? {
        guard let mySubclassPropertyValue = self.myKVOSubclass?.mySubclassProperty,
            let myKVOPropertyValue = self.myKVOProperty else { return nil }

        let myComputedKVOPropertyValue = NSString(format:"%@ %@",mySubclassPropertyValue, myKVOPropertyValue)
        return myComputedKVOPropertyValue as String
    }

    // MARK: Initialization

    @objc public required override init() {
        super.init()
    }

  // MARK: KVO

  public override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String>
  {
    if key == "myComputedKVOProperty" {
      return Set(["myKVOSubclass",
      "myKVOSubclass.mySubclassProperty",
      "myKVOProperty"])
    }
    // NOTE : Add more keys with the name of the property if needed...

    return Set([])
  }

}
于 2017-12-29T14:38:14.147 回答
0

谢谢黑暗奇迹。它适用于 Swift 4 !!!

之前- 将 didSet 添加到所有依赖属性:

class MyViewController: NSViewController {

  // bound to a Value of NSTextField with NumberFormatter
  @objc dynamic var amountOfBetOnRed: Int = 0 {
    didSet {
      updatebetButtonEnabled()
    }
  }

  // same above
  @objc dynamic var amountOfBetOnBlack: Int = 0 {
    didSet {
      updatebetButtonEnabled()
    }
  }

  // bound to a Enabled of NSButton
  @objc dynamic var betButtonEnabled: Bool = false

  func updatebetButtonEnabled() {
    betButtonEnabled = amountOfBetOnRed != 0 || amountOfBetOnBlack != 0
  }

}

之后- 用计算属性替换 didSet(s):

class MyViewController: NSViewController {

  @objc dynamic var amountOfBetOnRed: Int = 0

  @objc dynamic var amountOfBetOnBlack: Int = 0

  @objc dynamic var betButtonEnabled: Bool {
    get {
      return amountOfBetOnRed != 0 || amountOfBetOnBlack != 0
    }
  }

  override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
    print("Debug: called for:", key)

    switch key {
    case "betButtonEnabled" :
      return Set(["amountOfBetOnRed", "amountOfBetOnBlack"])
    default :
      return super.keyPathsForValuesAffectingValue(forKey: key)
    }
  }

}

get { }可以省略而直接离开return ...,但我get在这里强调它是一个计算属性。

用 Xcode 9.0 确认,上面的伪代码。

补充

到目前为止我学到了什么:该函数keyPathsForValuesAffectingValue被多次调用,@objc dynamic从 init() 返回后,每个属性名称都被一一指定。这种实现使我们能够判断哪些属性取决于哪些属性。实际上,addObserver是在幕后自动代表我们调用的。该函数不会为其他序数属性调用,例如 just varwithout @objc dynamic

于 2018-01-20T07:58:14.593 回答
0

这是 Swift 4 的更安全(因为#keyPath)、更短的版本:

override public class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
    return [
        #keyPath(Track.rTitle): [#keyPath(Track.title)],
        #keyPath(Track.rSource): [#keyPath(Track.album), #keyPath(Track.author)],
        ][key] ?? super.keyPathsForValuesAffectingValue(forKey: key)
}
于 2018-10-25T10:00:49.777 回答
-1

如果您只想检查名称或部门何时更新,只需使用 Swift 的dynamic关键字,如下所示:

dynamic var firstName: String

然后,您可以按照采用 Cocoa 设计模式指南遵循 Apple 关于在 Swift 中采用键值观察的文档

概括:

  1. dynamic关键字添加到您要观察的任何属性。
  2. 根据 Apple 的文档创建一个全局上下文变量。
  3. 覆盖observeValueForKeyPath方法。
于 2015-02-02T07:26:16.480 回答