KeyPathsForValuesAffecting with NSManagedObject

Bonjour, I would like to translate the exercise “Target” from Aaron’s book into a quick one, but I can’t find a solution. Objective'c Code:

@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]; } 

I found the function in the developer documentation, but I cannot figure out how to implement this code.

to be more explicit this is an apple document

Mutual relations

To automatically trigger notifications for a mutual relationship, you must either override keyPathsForValuesAffectingValueForKey: or implement a suitable method that follows the template that it defines for registering dependent keys.

For example, a person’s full name depends on both the name and the name. A method that returns the full name can be written as follows:

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

An application that monitors the fullName property must be notified when the firstName or lastName properties change, since they affect the value of the property.

One solution is to override keyPathsForValuesAffectingValueForKey: indicating that the person’s fullName property depends on the lastName and firstName properties. Listing 1 shows an example implementation of this dependency:

Listing 1 Example implementation of 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 

Can someone tell me how to implement this function in swift?

Thanks for helping me.

+5
source share
5 answers

I found a solution to my problem! Just override func keyPathsForValuesAffectingValueForKey (key: String) with class to

Here is the code:

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

Thanks for the help Yang

+5
source

To solve Swift 2:

 dynamic var firstName: String = "" dynamic var lastName: String = "" dynamic var fullName: String { return "\(firstName) \(lastName)" } class func keyPathsForValuesAffectingFullName() -> Set<String> { return Set(["firstName", "lastName"]) } 
+2
source

This solution works for Xcode 9+ and Swift 4.0 (Apple Swift version 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([]) } } 
+1
source

If you just want to check when the names or department are updated, just use Swift dynamic like this:

 dynamic var firstName: String 

You can then follow the Apple documentation on accepting key value monitoring in Swift by following the Cocoa Acceptance Design Patterns Guide

Summary:

  • Add the dynamic keyword to any property that you want to observe.
  • Create a global context variable according to Apple documentation.
  • Override observeValueForKeyPath method.
0
source

Thanks Darkwonder. He works in Swift 4 !!!

Before - adding hasSet to all dependent properties:

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

After - Replacing didSet (s) with a computed property:

 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 { } can be omitted and just leave return ... , but I used get here to emphasize that this is a computed property.

Confirmed using Xcode 9.0 with pseudo-code, as shown above.

Added

What I have learned so far: The keyPathsForValuesAffectingValue function keyPathsForValuesAffectingValue called several times with each property name specified as @objc dynamic one after the other after returning from init (). This implementation allows us to determine which properties depend on which properties. In fact, addObserver automatically called on behalf of us behind the scenes. This function is not called for other ordinal properties, such as just var without @objc dynamic .

0
source

Source: https://habr.com/ru/post/1212413/


All Articles