2013-08-17 4 views
2

У меня есть очень простой пример, когда я читаю некоторые данные в классе из JSON, и мои объекты каким-то образом повреждаются. Я подозреваю, что мне не хватает деталей о том, как работают свойства/ARC, но я не уверен, что это такое или как я его отслеживаю.Почему мои объекты неожиданно меняются?

Я сократил свой первоначальный код, так что проблема очевидна. Однако это означает, что неясно, почему я использую пользовательские свойства и т. Д. - мой реальный код имеет больше функциональности ...

Проблема может быть видна в последней строке файла Test.m. Первый построенный объект теперь содержит данные из второго объекта, а не значение, которое оно изначально содержало.

Любые советы о том, что я делаю неправильно и/или как отследить этот вопрос, были бы весьма признательны.

ANBNote.h

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

ANBNote.m

#import "ANBNote.h" 

@implementation ANBNote 
NSArray * _references; 

-(id) init { 
    if(!(self=[super init])) return nil; 
    [email protected][]; 
    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

... 
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! 

Обратите внимание, что если удалить корка om ссылается на функции свойств и полагается на сгенерированную версию компилятора, все, кажется, ведет себя правильно.

ответ

2

Это не Ивар:

@implementation ANBNote 
NSArray * _references; 

это глобальный. Для всех экземпляров вашего класса есть только один, а не один для каждого. Когда следующий экземпляр устанавливает его, предыдущие экземпляры видят новые значения, потому что это одна и та же переменная. Вы должны поместить его в фигурные скобки, чтобы сделать его Ивар:

@implementation ANBNote 
{ 
    NSArray * _references; 
} 

Там нет необходимости объявлять переменную явно, хотя - вы можете реализовать Accessors себя, и пусть компилятор создает Ивар до тех пор, как вы используйте синтезированное имя по умолчанию (имя underscore + имя свойства).

+0

Проблема с глобальными vs ivars находится на месте, и добавление ее в качестве ivar с использованием '{}' отлично работает. Но если я удалю определение ivar, я теперь получаю «Использование незаявленных идентифицированных« _references »... –

+0

Ваш компилятор не должен поддерживать автоматический синтез. В зависимости от его точной версии вы можете выполнять только «ссылки @synthesize», чтобы иметь ivar, созданный с помощью подчеркивания, или (если он достаточно старый), вам действительно придется объявить ivar отдельно, а затем соединить их с '@synthesize references = _references;' –

+0

В этом случае вы не можете опустить ivar: из http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html " Примечание. ... Если вы реализуете как getter, так и setter для свойства readwrite или getter для свойства readonly, компилятор будет считать, что вы берете контроль над реализацией свойства и не будете автоматически синтезировать переменную экземпляра. Если вам все еще нужна переменная экземпляра, вам необходимо запросить ее синтез: '@synthesize property = _property;' " –

2

Ответ прост, вы определили NSArray * _references как статическую переменную не как частную переменную. Для того, чтобы сделать это

@implementation ANBNote{ 
    NSArray * _references; 
} 

В дополнение к этому, как из Xcode 4 вам не нужно определить _references объект в файле реализации. Вы можете просто установить переменную в файл заголовка, а затем получить доступ к ее частному помощнику, просто набрав _ перед его именем.

Например

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

@implementation ANBNote 

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

@end 
+0

Пятно о проблеме статического vs ivar - однако, если я удалю определение в разделе '@implementation {...}', я получаю сообщение об ошибке «Использование необъявленного идентификатора» _references; 'error. Я что-то упускаю? Опять же этот вопрос уходит, если я не определяю какие-либо пользовательские функции getter/setter, но в моем реальном коде они обязательно необходимы. –

+0

, если вы установили пользовательский getter и setter, вы можете просто переопределить -setReferences: (NSArray *) ссылки {...} и метод get. Вам не нужно писать NSArray * _references; снова в вашей реализации. Кстати, я написал @property (сильный, неатомный) NSArray * ссылки на ваш файл заголовка – kkocabiyik

+0

Кажется, упущение совета ivar неверно: из http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html "Примечание. ... Если вы реализуете как getter, так и setter для свойства readwrite или getter для свойства readonly, компилятор предположит, что вы берете контроль над реализацией свойств и выигрываете 't автоматически синтезирует переменную экземпляра. Если вам все еще нужна переменная экземпляра, вам нужно запросить ее синтез: '@synthesize property = _property;' " –

0

Это не корень YOUT проблемы, но изменить initWithJson: к

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

Рву настраиваемое и присваивателя (вы, очевидно, не нужны).

В вашем случае вы можете объявить свойство просто с:

@property (strong) NSArray* references; 

Измените NSArray * _references; на:

@synthesize references = _references; 

Вы также можете опустить @synthesize строку в вашем случае.

изменить Также _references = jsonObject[@"references"]; на:

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

Резюмируя все это вместе:

ANBNote.h

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

ANBNote.m

#import "ANBNote.h" 

@implementation ANBNote 

-(id) init { 
    if(!(self=[super init])) return nil; 
    _refere[email protected][]; 
    return self; 
} 

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

@end 
+0

Спасибо за ваши комментарии, однако вы, должно быть, пропустили часть моего оригинального сообщения, в котором говорится: «Я сократил свой исходный код, так что проблема очевидна. Однако это означает, что неясно, почему я использую c свойства ustom и т. д. - мой реальный код имеет больше функциональности там ... »- не использование пользовательских getter/seters не является для меня вариантом из-за этой дополнительной функциональности. –

Смежные вопросы