是否可以在 objective C 中为静态变量设置 KVO 通知?
Is it possible to set up KVO notifications for static variables in objective C?
我有 class A,实例变量从缓存数据派生属性,这个缓存数据表示为单例并且是 A 的一部分(它本质上是一个 NSDictionary)。有时,此缓存会被修改。
发生这种情况时,我希望所有 A 实例在下次访问它们的属性时从缓存中提取新信息,或者换句话说,使它们的属性内容无效。
到目前为止,每个实例都是手动通知的(使用静态数组来跟踪成员)。我不是粉丝。通知中心可能有一个选项,但我宁愿尝试使用 KVO。
有没有人设法从 iOS 上的 class 变量订阅 KVO 更改? (换句话说,使用 A 的静态变量的更改来告诉 A 实例刷新它们的数据。)
换句话说,我很想
static void* context = &context;
static myHadHocObject* msignal;
以后在Class一个代码
[msignal addObserver:self forKeyPath:@"operation" options:NSKeyValueObservingOptionNew context:context];
并通过
收到 class 实例中 msignal 变化的通知
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
}
我试过使用各种 had hoc classes,但没有成功。好像我错过了什么。
欢迎指点,谢谢!
KVO 表示一个特定的对象观察另一个对象(或它自己)的 属性 的变化。所以我认为你想要达到的目标是不可能的,至少不是这样。或者至少你需要深入了解KVO机制。
您可以从 Apple Key-Value Observing Programming Guide
获得回答问题所需的所有信息
Unlike notifications that use NSNotificationCenter, there is no
central object that provides change notification for all observers.
Instead, notifications are sent directly to the observing objects when
changes are made. NSObject provides this base implementation of
key-value observing, and you should rarely need to override these
methods.
您可以使用 - willChangeValueForKey:
和 - didChangeValueForKey:
触发 KVO。您可以在 NSKeyValueObserving Protocol Reference
阅读更多相关信息
我建议您使用不同的方法,通过创建一个管理器来管理您的缓存并观察该缓存上的值,这只是一个例子。
CacheManager.h
#import <Foundation/Foundation.h>
@interface CacheManager : NSObject
@property (nonatomic, strong, readonly) NSArray *data;
+ (instancetype)sharedManager;
@end
CacheManager.m
#import "CacheManager.h"
@implementation CacheManager
- (instancetype)init {
if (self = [super init]) {
_data = [[NSArray alloc] init];
}
return self;
}
+ (instancetype)sharedManager {
static CacheManager *selfManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
selfManager = [[[self class] alloc] init];
});
return selfManager;
}
@end
ViewController.m
#import "ViewController.h"
#import "CacheManager.h"
static void *CacheManagerDataChangedContext = &CacheManagerDataChangedContext;
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CacheManager *cacheManager = [CacheManager sharedManager];
[cacheManager addObserver:self forKeyPath:NSStringFromSelector(@selector(data)) options:NSKeyValueObservingOptionNew context:CacheManagerDataChangedContext];
}
- (void)dealloc {
[[CacheManager sharedManager] removeObserver:self forKeyPath:NSStringFromSelector(@selector(data)) context:CacheManagerDataChangedContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == CacheManagerDataChangedContext) {
<# your stuff #>
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
如果您观察来自所有其他实例的 CacheManager 的 data
属性,当发生更改时,所有该实例都会收到通知。
希望对您有所帮助 ;)
以防万一,在不削弱@meligaletiko 优点的情况下,我正在编写完整解决方案的蓝图,对应于我的问题,以防它对任何人都有用。
问题是:给定 class 个使用从商店获取的数据副本的实例,如何在其中一个实例修改数据时有效地通知所有 class 个实例? (例如:数据来自 NSUserDefaults,但您不一定希望每次 fetch/save 数据 from/to 它,因为它很慢)此外,数据更改并不频繁。
来自@meligaletiko
#import <Foundation/Foundation.h>
@interface CacheManager : NSObject
@property (nonatomic, strong) NSString *data;
+ (instancetype)sharedManager;
@end
#import "CacheManager.h"
@implementation CacheManager
- (instancetype)init {
if (self = [super init]) {
_data = @"x";
}
return self;
}
+ (instancetype)sharedManager {
static CacheManager *selfManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
selfManager = [[[self class] alloc] init];
});
return selfManager;
}
@end
static void *CacheManagerDataChangedContext = &CacheManagerDataChangedContext;
@interface A:NSObject
-(NSString*)sz;
-(void)setSz:(NSString*)sz;
@end
@interface A ()
@property (nonatomic,copy) NSString* sz;
@property (nonatomic) BOOL shouldFetchDataFromStore;
-(id)fetchDataForKey:(NSString*)key
@end
@implementation A
-(instancetype)init{
self = [super init];
if (self) {
[[CacheManager sharedManager] addObserver:self forKeyPath:NSStringFromSelector(@selector(data))
options:NSKeyValueObservingOptionNew
context:CacheManagerDataChangedContext];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == CacheManagerDataChangedContext) {
self.shouldFetchDataFromStore = YES;
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
-(void)dealloc{
[[CacheManager sharedManager] removeObserver:self forKeyPath:NSStringFromSelector(@selector(data)) context:CacheManagerDataChangedContext];
}
-(void)setSz:(NSString*)sz{
_sz = sz;//sanity checks spared...
[CacheManager sharedManager].data = @"x";//this line will notify all other instances
}
-(NSString*)sz{
if(self.shouldFetchDataFromStore) { // in other class instances, this was updated to YES, thanks to KVO
self.shouldFetchDataFromStore = NO;
_sz = (NSString*)[self fetchDataForKey:(NSString*)sz];//updates _sz with the correct value.
}
return _sz;
}
@end
我有 class A,实例变量从缓存数据派生属性,这个缓存数据表示为单例并且是 A 的一部分(它本质上是一个 NSDictionary)。有时,此缓存会被修改。
发生这种情况时,我希望所有 A 实例在下次访问它们的属性时从缓存中提取新信息,或者换句话说,使它们的属性内容无效。
到目前为止,每个实例都是手动通知的(使用静态数组来跟踪成员)。我不是粉丝。通知中心可能有一个选项,但我宁愿尝试使用 KVO。
有没有人设法从 iOS 上的 class 变量订阅 KVO 更改? (换句话说,使用 A 的静态变量的更改来告诉 A 实例刷新它们的数据。)
换句话说,我很想
static void* context = &context;
static myHadHocObject* msignal;
以后在Class一个代码
[msignal addObserver:self forKeyPath:@"operation" options:NSKeyValueObservingOptionNew context:context];
并通过
收到 class 实例中 msignal 变化的通知-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
}
我试过使用各种 had hoc classes,但没有成功。好像我错过了什么。
欢迎指点,谢谢!
KVO 表示一个特定的对象观察另一个对象(或它自己)的 属性 的变化。所以我认为你想要达到的目标是不可能的,至少不是这样。或者至少你需要深入了解KVO机制。
您可以从 Apple Key-Value Observing Programming Guide
获得回答问题所需的所有信息Unlike notifications that use NSNotificationCenter, there is no central object that provides change notification for all observers. Instead, notifications are sent directly to the observing objects when changes are made. NSObject provides this base implementation of key-value observing, and you should rarely need to override these methods.
您可以使用 - willChangeValueForKey:
和 - didChangeValueForKey:
触发 KVO。您可以在 NSKeyValueObserving Protocol Reference
我建议您使用不同的方法,通过创建一个管理器来管理您的缓存并观察该缓存上的值,这只是一个例子。
CacheManager.h
#import <Foundation/Foundation.h>
@interface CacheManager : NSObject
@property (nonatomic, strong, readonly) NSArray *data;
+ (instancetype)sharedManager;
@end
CacheManager.m
#import "CacheManager.h"
@implementation CacheManager
- (instancetype)init {
if (self = [super init]) {
_data = [[NSArray alloc] init];
}
return self;
}
+ (instancetype)sharedManager {
static CacheManager *selfManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
selfManager = [[[self class] alloc] init];
});
return selfManager;
}
@end
ViewController.m
#import "ViewController.h"
#import "CacheManager.h"
static void *CacheManagerDataChangedContext = &CacheManagerDataChangedContext;
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CacheManager *cacheManager = [CacheManager sharedManager];
[cacheManager addObserver:self forKeyPath:NSStringFromSelector(@selector(data)) options:NSKeyValueObservingOptionNew context:CacheManagerDataChangedContext];
}
- (void)dealloc {
[[CacheManager sharedManager] removeObserver:self forKeyPath:NSStringFromSelector(@selector(data)) context:CacheManagerDataChangedContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == CacheManagerDataChangedContext) {
<# your stuff #>
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
如果您观察来自所有其他实例的 CacheManager 的 data
属性,当发生更改时,所有该实例都会收到通知。
希望对您有所帮助 ;)
以防万一,在不削弱@meligaletiko 优点的情况下,我正在编写完整解决方案的蓝图,对应于我的问题,以防它对任何人都有用。
问题是:给定 class 个使用从商店获取的数据副本的实例,如何在其中一个实例修改数据时有效地通知所有 class 个实例? (例如:数据来自 NSUserDefaults,但您不一定希望每次 fetch/save 数据 from/to 它,因为它很慢)此外,数据更改并不频繁。
来自@meligaletiko
#import <Foundation/Foundation.h>
@interface CacheManager : NSObject
@property (nonatomic, strong) NSString *data;
+ (instancetype)sharedManager;
@end
#import "CacheManager.h"
@implementation CacheManager
- (instancetype)init {
if (self = [super init]) {
_data = @"x";
}
return self;
}
+ (instancetype)sharedManager {
static CacheManager *selfManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
selfManager = [[[self class] alloc] init];
});
return selfManager;
}
@end
static void *CacheManagerDataChangedContext = &CacheManagerDataChangedContext;
@interface A:NSObject
-(NSString*)sz;
-(void)setSz:(NSString*)sz;
@end
@interface A ()
@property (nonatomic,copy) NSString* sz;
@property (nonatomic) BOOL shouldFetchDataFromStore;
-(id)fetchDataForKey:(NSString*)key
@end
@implementation A
-(instancetype)init{
self = [super init];
if (self) {
[[CacheManager sharedManager] addObserver:self forKeyPath:NSStringFromSelector(@selector(data))
options:NSKeyValueObservingOptionNew
context:CacheManagerDataChangedContext];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == CacheManagerDataChangedContext) {
self.shouldFetchDataFromStore = YES;
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
-(void)dealloc{
[[CacheManager sharedManager] removeObserver:self forKeyPath:NSStringFromSelector(@selector(data)) context:CacheManagerDataChangedContext];
}
-(void)setSz:(NSString*)sz{
_sz = sz;//sanity checks spared...
[CacheManager sharedManager].data = @"x";//this line will notify all other instances
}
-(NSString*)sz{
if(self.shouldFetchDataFromStore) { // in other class instances, this was updated to YES, thanks to KVO
self.shouldFetchDataFromStore = NO;
_sz = (NSString*)[self fetchDataForKey:(NSString*)sz];//updates _sz with the correct value.
}
return _sz;
}
@end