2012-04-20 7 views
7

Ho un problema in cui ottengo eccezioni di accesso errate ma solo quando si esegue una build di test (chiamando gli stessi metodi in una build di debug non si verifica il problema). Il progetto ha permesso ARC e sto correndo questo sul simulatore di iPad 5.1 con Xcode 4.3:EXC_BAD_ACCESS utilizzando ARC durante il test

Ecco dove il problema pota in su:

- (void)testChangeFoodNotification { 
    Player* p = [[Player alloc] init]; 
    [p addObserver:self forKeyPath:@"food" options:0 context:0]; // <-EXC_BAD_ACCESS (code=2) 
    p.food += 1; 
    STAssertTrue(_wasNotifiedOfFoodChange, nil); 
} 

Nel momento in cui il metodo addObserver: viene chiamato doesn' Sembra che tutti gli oggetti coinvolti siano stati rilasciati, quindi cosa potrebbe causare l'eccezione?

EDIT:

Scuse se non è chiaro, ma il codice precedente viene eseguito come parte di un banco di prova (usando l'Xcode OCUnit standard). Anche nel caso in cui chiarisce nulla ecco il relativo codice dalla classe giocatore (non c'è altro Ivars e metodi, ma non hanno alcun collegamento con la proprietà o metodi in fase di test):

// Public interface 
@interface Player : NSObject 

@property (nonatomic, assign) NSInteger food; 

@end 

// Private interface 
@interface Player() { 
    NSInteger _food; 
} 

@end 

@implementation Player 

@synthesize food = _food; 

#pragma mark - Getters/Setters 

- (void)setFood:(NSInteger)food { 
    [self willChangeValueForKey:@"food"]; 
    _food = food; 
    [self didChangeValueForKey:@"food"];  
} 

risposta

21

Se la classe è effettivamente conforme ai valori chiave, assicurarsi che l'implementazione per la classe che presenta il problema non sia inclusa nel prodotto di prova. Ciò significa che il pannello Target Membership della finestra di ispezione Identità per il tuo file .m deve avere solo la tua app controllata (non YourAppTests).

Ho riscontrato lo stesso problema in Xcode 4.3.1 quando un'implementazione è stata inclusa in entrambi i prodotti e ho registrato osservatori nel codice di produzione e di test. I seguenti registri mi soffiata:

Classe YourClass è implementato in entrambi/supportare gli utenti/youruser/Library/Application/iPhone Simulator/5.1/Applicazioni // YourApp.app/YourApp e/Users/youruser/Library/Developer/Xcode/DerivedData/YourApp-/build/Prodotti/Debug-iphonesimulator/YourAppTests.octest/YourAppTests. Uno dei due sarà usato. Quale è indefinito.

+3

Vorrei poter sopravvivere questo 100 volte. Grazie! – DexterW

+0

Ho riscontrato questo problema anche con CocoaPods. Il file di implementazione della classe è stato incluso nei pod sia per l'app che per la destinazione dell'app test, tranne che nei registri non era presente alcun avviso di classe duplicato. – Eric

0

Come per la Key-Value Observing Programming Guide, è il tuo lettore chiave valore-compatibile? Vuoi assicurarti di essere Ensuring KVC Compliance. Suppongo anche che tu abbia implementato anche il tuo observeValueForKeyPath:ofObject:change:context:? Se pensi di aver fatto tutto questo e ancora non funziona, allora forse puoi condividere il tuo codice.

Inoltre, cosa minore, ma presumo che questo sia uno snippet di codice per evidenziare il problema. Lo cito solo perché ARC rilascerà il tuo oggetto p alla fine del testChangeFoodNotification e avrei pensato che volessi rimuovere prima il tuo osservatore.

+0

Grazie per la risposta. Potrei mancare qualcosa ma penso che la classe sia conforme a KVC (il fatto che lo stesso codice funzioni al di fuori di una build di test mi fa pensare che sia conforme ma potrei sbagliarmi - questa è la mia prima volta che uso KVC/KVO). Per quanto riguarda la rimozione dell'osservatore. Normalmente lo farei ma ho pensato che siccome questo è un metodo di test case e sia l'operatore che l'osservatore saranno distrutti prima che ci sia la possibilità di modificare p di nuovo, sarebbe meglio evitare di ingombrare il metodo di test con boilerplate. Potrei sbagliarmi e se lo sono, mi piacerebbe sapere come;) – Mattia

+0

Sì, non lo vedo. Scusate. Non capisco perché tu stia definendo la tua interfaccia privata per _food né perché tu scriva il tuo setter (la dichiarazione @synthesize fa entrambe le cose per te), ma dubiti che questa sia la fonte del problema. Ancora più importante, non capisco perché si ottiene un comportamento diverso nelle build di debug di test. Posso solo suggerirti di attivare gli zombi modificando il tuo schema nella build del test, se non lo hai già fatto, e vedere se è più illuminante. – Rob

+0

Originariamente non aggiungevo i miei setter ma li ho aggiunti per vedere se fosse questo il problema (ho pensato che forse quelli sintetizzati non chiamavano will/didChangeValueForKey - che non sembra essere il caso). Il motivo per cui dichiaro la mia variabile privata è abitudine: mi piacciono i miei ivar con caratteri di sottolineatura e il compilatore li sintetizza senza il trattino di sottolineatura. In ogni caso grazie per dare un'occhiata. – Mattia