Objective c 观察上下文的键值无效
在Objective-C中,当使用键值观察时,我有一个带有AccountHome属性和person属性的银行类。增加该人员以观察国内财产账户。我在Bank类中有一个Objective c 观察上下文的键值无效,objective-c,key-value-observing,Objective C,Key Value Observing,在Objective-C中,当使用键值观察时,我有一个带有AccountHome属性和person属性的银行类。增加该人员以观察国内财产账户。我在Bank类中有一个静态void*bankContext=&bankContext作为其上下文。但是,在我更改AccountHomeland属性后,由于对象的-(void)observeValueForKeyPath:(NSString*)键路径:(id)对象更改:(NSDictionary*)更改上下文:(void*)上下文方法中的上下文和bankCo
静态void*bankContext=&bankContext
作为其上下文。但是,在我更改AccountHomeland属性后,由于对象的-(void)observeValueForKeyPath:(NSString*)键路径:(id)对象更改:(NSDictionary*)更改上下文:(void*)上下文
方法中的上下文和bankContext不匹配,因此无法正确显示新旧值
代码如下,首先是银行类:
Bank.h
#import <Foundation/Foundation.h>
#import "Person.h"
static void * const bankContext = &bankContext;
@class Person;
@interface Bank : NSObject
@property (nonatomic, strong) NSNumber* accountDomestic;
@property (nonatomic, strong) Person* person;
-(instancetype)initWithPerson:(Person *)person;
@end
Bank.m
@implementation
-(instancetype)initWithPerson:(Person *)person{
if(self = [super init]){
_person = person;
[self addObserver:_person
forKeyPath:NSStringFromSelector(@selector(accountDomestic))
options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew
context:bankContext];
}
return self;
}
-(void)dealloc{
[self removeObserver:_person forKeyPath:NSStringFromSelector(@selector(accountDomestic))];
}
@end
Bank.h
#进口
#输入“Person.h”
静态void*const bankContext=&bankContext;
@班主任;
@接口库:NSObject
@属性(非原子,强)NSNumber*AccountNational;
@财产(非原子、强)人*人;
-(instancetype)initWithPerson:(Person*)Person;
@结束
m银行
@实施
-(instancetype)initWithPerson:(Person*)Person{
if(self=[super init]){
_人=人;
[自我添加观察者:\u个人
forKeyPath:NSStringFromSelector(@selector(AccountHome))
选项:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
上下文:bankContext];
}
回归自我;
}
-(无效)解除锁定{
[self-removeObserver:_PersonForkeyPath:NSStringFromSelector(@selector(AccountHome))];
}
@结束
然后是Person类:
Person.h
#import <Foundation/Foundation.h>
#import "Bank.h"
@interface Person : NSObject
@end
Person.m
#import "Person.h"
@implementation Person
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"context: %p",context);
NSLog(@"bankContext: %p",bankContext);
if(context == bankContext){
if([keyPath isEqualToString:NSStringFromSelector(@selector(accountDomestic))]){
NSString *oldValue = change[NSKeyValueChangeOldKey];
NSString *newValue = change[NSKeyValueChangeNewKey];
NSLog(@"--------------------------");
NSLog(@"accountDomestic old value: %@", oldValue);
NSLog(@"accountDomestic new value: %@", newValue);
}
}
}
@end
Person.h
#进口
#输入“Bank.h”
@接口人:NSObject
@结束
人
#输入“Person.h”
@执行人
-(void)observeValueForKeyPath:(NSString*)对象的键路径:(id)对象更改:(NSDictionary*)更改上下文:(void*)上下文{
NSLog(@“上下文:%p”,上下文);
NSLog(@“bankContext:%p”,bankContext);
if(context==bankContext){
if([keyPath IsequalString:NSStringFromSelector(@selector(AccountHome))])){
NSString*oldValue=change[NSKeyValueChangeOldKey];
NSString*newValue=change[NSKeyValueChangeNewKey];
NSLog(@“-----------------------------------”);
NSLog(@“会计国内旧值:%@”,旧值);
NSLog(@“Account国内新值:%@”,新值);
}
}
}
@结束
最后是ViewController类
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m
#import "ViewController.h"
#import "Bank.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic, strong) Bank *bank;
@property (nonatomic, strong) Person *person;
@property (nonatomic, strong) NSNumber *delta;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[Person alloc] init];
self.delta = @10;
self.bank = [[Bank alloc] initWithPerson:self.person];
}
- (IBAction)accountDomesticIncreaseButtonDidTouch:(id)sender {
self.bank.accountDomestic = self.delta;
int temp = [self.delta intValue];
temp += 10;
self.delta = [NSNumber numberWithInt:temp];
}
@end
ViewController.h
#进口
@界面ViewController:UIViewController
@结束
ViewController.m
#导入“ViewController.h”
#输入“Bank.h”
#输入“Person.h”
@界面视图控制器()
@不动产(非原子、强)银行*银行;
@财产(非原子、强)人*人;
@属性(非原子,强)NSNumber*delta;
@结束
@实现视图控制器
-(无效)viewDidLoad{
[超级视图下载];
self.person=[[person alloc]init];
self.delta=@10;
self.bank=[[bank alloc]initWithPerson:self.person];
}
-(iAction)AccountDomesticEncreateButtondTouch:(id)发件人{
self.bank.account国内=self.delta;
int temp=[self.delta intValue];
温度+=10;
self.delta=[NSNumber numberwhithint:temp];
}
@结束
单击按钮后,AccountHomeal的新值和旧值均未显示。您可以看到context和bankContext值不相等,如下图所示:
有人知道吗?原因是有两个
bankContext
s。在Bank.h
中,您有
static void*const bankContext=&bankContext;
然后,该文件同时包含在Bank.m
和Person.m
中,因此这两个文件(编译单元)都定义了一个指针bankContext
,该指针标记为static
,因此不会生成外部链接(因此可以有两个同名指针)
最直接的解决方案是确保只有一个bankContext
。在Bank.h
中:
extern void*const bankContext;
而在银行m中:
void*const bankContext=&bankContext;
也就是说,我认为最好重新构造代码,这样就没有必要了。你的职责设置让我很警惕(一个对象告诉另一个对象成为观察者),我很惊讶它编译正确,因为似乎存在循环导入(
Bank.h
和Person.h
相互导入)。如果你使用静态对象,那么这个类如果有效地简化为单例。为什么要这样限制类?本文建议这样做。作为象征。如果我不关心同一个类的不同实例,我认为这很好。关键是为什么contex和bankContext不相等。啊,好吧,我错了。我收回:)你说的是对的!使用bankContext=&bankContext的目的是作为特定类()的标记。为此,我认为可以使用if(objectiskindofclass:[Bank class]])
比if([context==bankContext)更好
无需额外的bankContext变量声明。我建议您继续使用NSHipster文章中建议的上下文指针。您需要学习更多关于C中变量存储的知识,以便将其正确应用于您的情况。感谢您的建议,我已经看到了静态和外部变量之间的区别。难道不需要声明吗上下文指针只是用来标识情况的标记?据我所知,我看不到其他优势。它不是严格必需的,但会更加健壮,因为如果只检查对象和键路径,超类或子类(甚至可能是其他对象)也可能设置可能会干扰的观察。