keyPathsForValuesAffecting 与 NSManagedObject
keyPathsForValuesAffecting with NSManagedObject
您好,
我想将 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 文档
To-one Relationships
要自动触发一对一关系的通知,您应该重写 keyPathsForValuesAffectingValueForKey: 或实现一个合适的方法,该方法遵循它为注册相关键定义的模式。
例如,一个人的全名取决于名字和姓氏。 returns全名可以这样写的方法:
- (NSString *)fullName {
return [NSString stringWithFormat:@"%@ %@",firstName, lastName];
}
观察 fullName 属性 的应用程序必须在 firstName 或 lastName 属性更改时得到通知,因为它们会影响 属性.
的值
一种解决方案是覆盖 keyPathsForValuesAffectingValueForKey:指定一个人的全名 属性 取决于 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
谁能告诉我如何在 swift 中实现这个功能?
谢谢你帮助我。
如果您只想检查名称或部门何时更新,只需使用 Swift 的 dynamic
关键字,如下所示:
dynamic var firstName: String
然后您可以按照 Adopting Cocoa Design Patterns Guide
在 Swift 中遵循 Apple 关于采用键值观察的文档
总结:
- 将
dynamic
关键字添加到您要观察的任何 属性。
- 根据 Apple 文档创建全局上下文变量。
- 覆盖
observeValueForKeyPath
方法。
我找到了问题的解决方案!
只需在
之前用 class 覆盖 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)
}
}
感谢您的帮助
一月
对于Swift4的解决方案是:
@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"])
}
此解决方案适用于 XCode 9+ 和 Swift 4.0(Apple Swift 版本 4.0.2(swiftlang-900.0. 69.2 铿锵声-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([])
}
}
谢谢 Darkwonder。它适用于 Swift 4!!!
Before - 将 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
}
}
After - 用计算的 属性:
替换 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
在从 init() 返回后被调用了几次,每个 属性 名称被一个一个指定为 @objc dynamic
。这个实现让我们知道哪些属性依赖于哪些属性。实际上,addObserver
是在幕后代表我们自动调用的。其他序数属性不会调用该函数,例如 var
而没有 @objc dynamic
.
这里有一个更安全的(因为#keyPath),Swift 4 的更短版本:
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)
}
您好, 我想将 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 文档
To-one Relationships
要自动触发一对一关系的通知,您应该重写 keyPathsForValuesAffectingValueForKey: 或实现一个合适的方法,该方法遵循它为注册相关键定义的模式。
例如,一个人的全名取决于名字和姓氏。 returns全名可以这样写的方法:
- (NSString *)fullName {
return [NSString stringWithFormat:@"%@ %@",firstName, lastName];
}
观察 fullName 属性 的应用程序必须在 firstName 或 lastName 属性更改时得到通知,因为它们会影响 属性.
的值一种解决方案是覆盖 keyPathsForValuesAffectingValueForKey:指定一个人的全名 属性 取决于 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
谁能告诉我如何在 swift 中实现这个功能?
谢谢你帮助我。
如果您只想检查名称或部门何时更新,只需使用 Swift 的 dynamic
关键字,如下所示:
dynamic var firstName: String
然后您可以按照 Adopting Cocoa Design Patterns Guide
在 Swift 中遵循 Apple 关于采用键值观察的文档总结:
- 将
dynamic
关键字添加到您要观察的任何 属性。 - 根据 Apple 文档创建全局上下文变量。
- 覆盖
observeValueForKeyPath
方法。
我找到了问题的解决方案! 只需在
之前用 class 覆盖 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)
}
}
感谢您的帮助 一月
对于Swift4的解决方案是:
@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"])
}
此解决方案适用于 XCode 9+ 和 Swift 4.0(Apple Swift 版本 4.0.2(swiftlang-900.0. 69.2 铿锵声-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([])
}
}
谢谢 Darkwonder。它适用于 Swift 4!!!
Before - 将 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
}
}
After - 用计算的 属性:
替换 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
在从 init() 返回后被调用了几次,每个 属性 名称被一个一个指定为 @objc dynamic
。这个实现让我们知道哪些属性依赖于哪些属性。实际上,addObserver
是在幕后代表我们自动调用的。其他序数属性不会调用该函数,例如 var
而没有 @objc dynamic
.
这里有一个更安全的(因为#keyPath),Swift 4 的更短版本:
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)
}