简体   繁体   English

为什么我的对象发生意外变化?

[英]Why are my objects changing unexpectedly?

I've got a very basic example where I'm reading some data into a class from JSON, and my objects are getting corrupted somehow. 我有一个非常基本的示例,其中我从JSON读取一些数据到类中,并且我的对象以某种方式被损坏。 I suspect I'm missing some detail about how properties/ARC is working, but I'm not sure what it is, or how I'd track it down. 我怀疑我缺少有关properties / ARC如何工作的详细信息,但是我不确定它是什么,或者如何跟踪它。

I've reduced my original code so that the problem is obvious. 我减少了原始代码,以使问题显而易见。 However this means that its not clear why I'm using custom properties etc. - my real code has more functionality in there... 但是,这意味着不清楚为什么我要使用自定义属性等。-我的真实代码在其中具有更多功能...

The issue can be seen in the last line of the Test.m file. 可以在Test.m文件的最后一行看到此问题。 The first constructed object now contains data from the second object rather than the value it originally contained. 现在,第一个构造的对象包含第二个对象的数据,而不是它最初包含的值。

Any advice on what I'm doing wrong and/or how to track down this kind of issue would be greatly appreciated. 对于我做错了什么和/或如何查找此类问题的任何建议,将不胜感激。

ANBNote.h ANBNote.h

@interface ANBNote : NSObject
@property (nonatomic,readwrite) NSArray* references;
- (id)initWithJson:(NSDictionary*)data;
@end

ANBNote.m ANBNote.m

#import "ANBNote.h"

@implementation ANBNote
NSArray * _references;

-(id) init {
  if(!(self=[super init])) return nil;
  _references=@[];
  return self;
}

-(id)initWithJson:(NSDictionary *)jsonObject {      
  if(!(self = [self init] ) ) { return nil; }    
  _references = jsonObject[@"references"];    
  return self;
}

-(void) setReferences:(NSArray *)references {
  _references = references;
}

-(NSArray *)references {
  return _references;
}    

@end

Test.m Test.m

...
NSDictionary * d1 = @{@"references":@[@"r1",@"r2"]};
NSDictionary * d2 = @{@"references":@[@"q1",@"q2"]};

ANBNote * n1 = [[ANBNote alloc] initWithJson:d1];
NSLog(@"R1 = %p, %@", n1.references, n1.references); // Prints r1, r2 - as expected

ANBNote * n2 = [[ANBNote alloc] initWithJson:d2];
NSLog(@"R2 = %p, %@", n2.references, n2.references); // Prints q1, q2 - as expected
NSLog(@"R1 = %p, %@", n1.references, n1.references); // Prints q1, q2 - Oh No!

Note that if I remove custom references property functions and rely on the compiler generated version everything seems to behave correctly. 请注意,如果我删除了自定义引用属性函数,并依赖于编译器生成的版本,那么一切似乎都表现正常。

This is not a ivar: 这不是一个ivar:

@implementation ANBNote
NSArray * _references;

it's a global. 这是全球性的。 There's only one for all the instances of your class, not one for each. 类的所有实例只有一个,而每个实例都没有。 When the next instance sets it, the previous instances see the new values because it's the same variable. 当下一个实例对其进行设置时,前一个实例将看到新值,因为它是相同的变量。 You need to put it into curly braces to make it an ivar: 您需要将其放在花括号中以使其成为ivar:

@implementation ANBNote
{
    NSArray * _references;
}

There's no need to declare the variable explicitly, though -- you can still implement accessors yourself and let the compiler create the ivar as long as you use the default synthesized name (underscore + property name). 但是,无需显式声明变量-只要您使用默认的综合名称(下划线+属性名称),您仍然可以自己实现访问器并让编译器创建ivar。

The answer is simple, you defined NSArray *_references as a static variable not as a private variable. 答案很简单,您将NSArray * _references定义为静态变量而不是私有变量。 To do that 要做到这一点

@implementation ANBNote{
    NSArray * _references;
}

In addition to this as of Xcode 4 you do not have to define _references object in the implementation file. 从Xcode 4开始,除此以外,您不必在实现文件中定义_references对象。 You may just set a variable in the header file and then access its private accessor by just typing _ before the name of it. 您可以在头文件中设置一个变量,然后通过在其名称之前键入_访问其私有访问器。

For instance 例如

@interface ANBNote
@property(strong , nonatomic) NSArray *references;
@end

@implementation ANBNote

-(id) initWithArray:(NSArray *) ar{
    if(self)
        _references = [NSArray arrayWithArray:ar];
    return self;
}

@end

This is not the root of yout problem but change your initWithJson: to 这不是问题的根源,而是将initWithJson:更改为

-(id)initWithJson:(NSDictionary *)jsonObject
{      
  if(!(self = [super init] ) ) { return nil; }    
  _references = jsonObject[@"references"];    
  return self;
}

Ditch the custom setter and getter (you obviously don't need them). 抛弃定制的setter和getter(您显然不需要它们)。

In your case you can declare property simply with: 您可以使用以下方法简单地声明属性:

@property (strong) NSArray* references;

Change the NSArray * _references; 更改NSArray * _references; to: 至:

@synthesize references = _references;

You can also omit the @synthesize line in your case. 您还可以根据情况省略@synthesize行。

Also change _references = jsonObject[@"references"]; 还要更改_references = jsonObject[@"references"]; to: 至:

_references = [NSArray arrayWithArray:jsonObject[@"references"]];

To sum it all together: 总结一下:

ANBNote.h ANBNote.h

@interface ANBNote : NSObject
@property (strong) NSArray* references;
- (id)initWithJson:(NSDictionary*)data;
@end

ANBNote.m ANBNote.m

#import "ANBNote.h"

@implementation ANBNote

-(id) init {
  if(!(self=[super init])) return nil;
  _references=@[];
  return self;
}

-(id)initWithJson:(NSDictionary *)jsonObject {      
  if(!(self = [super init] ) ) { return nil; }    
  _references = [NSArray arrayWithArray:jsonObject[@"references"]];    
  return self;
}

@end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM