2010-05-06 12 views
13
Aggiornamento

- Molte persone insistono che devo dichiarare un iVar per la proprietà. Alcuni stanno dicendo non così, come sto usando Modern Runtime (64 bit). Posso confermare che sto usando @property con successo senza iVars da mesi ormai. Pertanto, penso che la risposta 'corretta' sia una spiegazione del perché su 64bit improvvisamente devo dichiarare esplicitamente iVar quando (e solo quando) ho intenzione di accedervi da una classe figlia. L'unico che ho visto finora è un possibile bug di GCC (grazie a Yuji). Non è così semplice dopotutto ... Per chiarire il possibile bug è questo: quando si eredita da una classe base, un bambino non può accedere all'iVar del genitore se quel bambino capita anche di implementare un accessor UNRELATED usando @synthesize PRIMA dell'accesso di iVar.(Not So) Silly Objective-C problema di ereditarietà quando si utilizza la proprietà - Bug GCC?

Mi sono grattato la testa per un paio d'ore - non ho usato molto l'ereditarietà.

Qui ho impostato una semplice classe di test B che eredita dal test A, dove viene dichiarato un ivar. Ma ottengo l'errore di compilazione che la variabile non è dichiarata. Questo succede solo quando aggiungo la proprietà e sintetizzi le dichiarazioni - funziona senza di loro.

TestA Intestazione:

#import <Cocoa/Cocoa.h> 
@interface TestA : NSObject { 
    NSString *testString; 
} 
@end 

TestA L'implementazione è vuota:

#import "TestA.h" 
@implementation TestA 
@end 

TestB Intestazione:

#import <Cocoa/Cocoa.h> 
#import "TestA.h" 
@interface TestB : TestA { 
} 
@property (nonatomic, retain) NSString *testProp; 
@end 

TestB attuazione (Error - 'testString' è non dichiarato)

#import "TestB.h" 
@implementation TestB 
@synthesize testProp; 
- (void)testing{ 
    NSLog(@"test ivar is %@", testString); 
} 
@end 
+0

Se "accade solo quando [tu] aggiungi la proprietà e sintetizzi le dichiarazioni", non sono un'aringa rossa. Come ho già detto, in realtà causano il problema perché non esiste una variabile di istanza di stringa 'testProp'. Ho dichiarato uno e il problema è andato via. –

+0

Ho appena controllato per assicurarmi che non stavo diventando mentalmente, e uso @property senza un ivar tutto il tempo senza problemi. Sono d'accordo che dichiarare un ivar 'lo corregge', ma in realtà non spiega il motivo per cui non riesce a compilare solo quando utilizzo l'ereditarietà. Solo per ripetere, non sto dichiarando ivars per circa 50 proprietà all'interno dello stesso progetto, in molte classi diverse, tutte senza problemi. –

risposta

10

Penso che questo sia il bug di GCC 4.2.1. Ho fatto il file foo.m con il contenuto

#import <Foundation/Foundation.h> 
@interface TestA : NSObject { 
    NSString *testString; 
} 
@end 

@implementation TestA 
@end 

@interface TestB : TestA { 
} 
@property (retain) NSString *testProp; 
@end 

@implementation TestB 
@synthesize testProp; 
- (void)testing{ 
NSLog(@"test ivar is %@", testString); 
} 
@end 

Nota che è OK nella modalità a 64 bit per omettere la variabile di istanza. mio GCC 4.2.1 su OS X 10.6.3 mi ha dato un errore:

$ gcc -arch x86_64 -c foo.m 
aho.m: In function ‘-[TestB testing]’: 
aho.m:19: error: ‘testString’ undeclared (first use in this function) 
aho.m:19: error: (Each undeclared identifier is reported only once 
aho.m:19: error: for each function it appears in.) 

Questo compilato senza problema cambiando

NSLog(@"test ivar is %@", testString); 

a

NSLog(@"test ivar is %@", self->testString); 

Clang compilato senza alcun problema.

(Nella modalità a 32 bit, ho ottenuto

$ gcc -arch i386 -c foo.m 
aho.m:17: error: synthesized property ‘testProp’ must either be named 
the same as a compatible ivar or must explicitly name an ivar 
aho.m: In function ‘-[TestB testing]’: 
aho.m:19: error: ‘testString’ undeclared (first use in this function) 
aho.m:19: error: (Each undeclared identifier is reported only once 
aho.m:19: error: for each function it appears in.) 

che è un comportamento perfettamente prevedibile, come ha scritto Manjunath.)

Tuttavia penso che sia generalmente piuttosto cattiva idea per accedere a un variabile di istanza della superclasse: quando si implementano i metodi della superclasse, non si può assumere nulla sulla variabile di istanza perché potrebbe essere ottimizzata nel modo peggiore possibile dalla sottoclasse. Hai almeno bisogno di annotare quale tipo di operazione sulla variabile di istanza è consentita o meno ...Ricorda che potresti aver bisogno di mantenere il tuo codice per anni! Preferirei mantenere i contratti di programmazione tra varie parti del codice a livello di metodi e proprietà.

Infine si dovrebbe cambiare

@property NSString *testProp; 

a

@property (copy) NSString *testProp; 

o almeno a

@property (retain) NSString *testProp; 

se non si sta usando GC su OS X. In caso contrario EXP_BAD_ACCESS vi aspettano !

+0

La prima parte è errata; ma per la seconda parte: a meno che tu/hai bisogno di/per supportare l'accesso al thread, (qualunque sia, non anatomico) è anche suggerito. –

+1

Naaaah! Entrambi avete davvero compilato il file? Ho combinato tutto in un file '.m' e gcc ha dato l'errore. Modifico il post sopra per includere il file che ho usato. – Yuji

+0

Manjunath - Sto già importando la classe base ?! Vedi il codice sopra. –

1

penso che basta un errore di battitura - dovrebbe essere "testString" non "test"

+0

Grazie - hanno aggiornato. Il problema non era purtroppo, ma mi ha aiutato a restringerlo. –

1

Sto vedendo error: 'testString' undeclared (first use in this function) quando lo @synthesize è appena prima del metodo testing. L'errore scompare se sposto lo @synthesize sotto l'implementazione del metodo. Ciò potrebbe essere dovuto al fatto che la classe TestB non ha una variabile di istanza di stringa testProp da utilizzare con la proprietà dichiarata. (Nel runtime Legacy (32 bit), deve dichiarare le variabili di istanza da utilizzare per le proprietà: in Modern runtime (64-bit Mac, iPhone) è possibile dedurre, quindi dichiararle è facoltativo.) È possibile che intendevi nominare la proprietà testString invece?


EDIT: In GCC 4.2, funziona se si cambia TestB.h al seguente:

#import "TestA.h" 

@interface TestB : TestA { 
    NSString *testProp; // <-- Adding this fixes the errors 
} 
@property NSString *testProp; 

@end 

Tuttavia, utilizzando il compilatore Clang-LLVM, il codice funziona non modificato. Forse questo è un bug da archiviare.

+0

Sì, si tratta di un errore di copia e incolla, corretto. Ma ho usato le proprietà per 6 mesi senza dichiarare ivars?!? per esempio. @property (nonatomic, retain) –

+0

Oppure il retain lo fa? Ad ogni modo, non lo risolve purtroppo. –

+0

Non è necessario dichiarare variabili di istanza per le proprietà se si utilizza il runtime moderno. Il runtime moderno include il sistema operativo per iPhone e 64 bit su OS X. – Yuji

1

Mi sono imbattuto in quello stesso problema ma le fonti erano abbastanza complesse da non comprendere appieno cosa abbia reso inaccessibile iVar dal genitore quando ho usato GCC. Sapevo solo con certezza che alcuni mesi fa e prima che i cambiamenti nel mio codice funzionassero e che funzionasse anche con clang che uso da un po 'di tempo. All'improvviso ho dovuto costruire con GCC e non lo farebbe più.

Almeno questo articolo mi ha dato un bypass (dichiarare gli iVars). Sono sorpreso che l'ultima versione di XCode non includa un compilatore fisso

Problemi correlati