2012-09-03 13 views
10

vorrei aggiungere un alloggio ai UITableView in un'estensione Classe:Definizione di un immobile in estensione classe iOS

@interface UITableViewController() 

@property NSString *entityString; 

@end 

Poi importare l'estensione e poi utilizzare la proprietà entityString in una sottoclasse di UITableViewController:

@implementation CustomerTableViewController 

- (void)viewDidLoad { 
    self.entityString = @"Customer"; 
    ... 
    [super viewDidLoad]; 
} 
... 

Apple documentation dice:

the compiler will automatically synthesize the relevant accessor methods (...) inside the primary class implementation.

Ma quando provo a ex ecuto ho questo errore:

-[CustomerTableViewController setEntityString:]: unrecognized selector sent to instance 0x737b670

Cosa sto facendo di sbagliato? forse la proprietà non è accessibile per sottoclassi?

risposta

5

Un classe dell'estensione consente di dichiarare interfaccia aggiuntive - metodi e proprietà - il cui rapporto di attuazione saranno soddisfatte entro primario @implementaiton della classe.

Che è esattamente il motivo per cui non è possibile aggiungere spazio di archiviazione - aggiungere ivars - tramite un'estensione di classe. Un'estensione di classe è un'interfaccia, né più né meno. @synthesize è ciò che crea l'archiviazione per le dichiarazioni @property, ma @synthesize di un @property può apparire solo nello @implementation della classe (sia esplicitamente che come comportamento predefinito del compilatore).

Poiché non è possibile ricompilare la classe framework, non è possibile aggiungere ivar ad essa.

@ La risposta di prashat è un modo per aggiungere spazio di archiviazione a una classe esistente. Tuttavia, andare su quella rotta è generalmente indesiderabile; willy-nilly è un segno di design scadente e renderà la tua applicazione significativamente più difficile da mantenere nel tempo.

Molto meglio rivisitare il progetto, capire perché attualmente è necessario associare lo stato a un oggetto che non può contenerlo direttamente e rifattorizzare quel requisito.

+0

Impossibile aggiungere ivar all'estensione di classe o questo dipende dal compilatore utilizzato? – tiguero

+3

È possibile dichiarare ivars e proprietà nelle estensioni di classe, ma l'archiviazione per tali non verrà creata a meno che l'estensione non venga visualizzata dal compilatore prima della compilazione di @implementation della classe. – bbum

+0

Grazie per il chiarimento - non ho notato che alazaro stava usando un'estensione di classe per una classe di framework effettivamente – tiguero

4

Lo stato docs:

Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main @implementation block for the corresponding class.

Quando si utilizza @property, è grosso modo equivalente a dichiarando metodi di accesso. Quindi questo significa che puoi fare una cosa del genere solo se sei anche l'autore del blocco "principale" @implementation della classe, che con UITableViewController non sei.

L'unica opzione qui è Categorie, che non possono aggiungere variabili di istanza.

The docs link, e notare l'ultima riga di questa pagina:

The implementation of the setValue: method must appear within the main @implementation block for the class (you cannot implement it in a category). If this is not the case, the compiler emits a warning that it cannot find a method definition for setValue:.

+0

Penso che non sia il mio caso, non sto usando un accessor ivar +. Tuttavia, il compilatore non si lamenta del mio codice. L'errore è in fase di esecuzione. – alazaro

+3

un '@ property' ** è ** un ivar più accessori. –

+0

Sì, lo so, ma il compilatore fa il lavoro per voi. Ho pensato che potesse aggiungere anche accessor nella classe principale, non importa se mi appartiene o meno. – alazaro

12

provare a utilizzare un categoria con invece associativi Riferimenti. È molto più pulito e funzionerà su tutte le istanze di UIButton.

UIButton+Property.h 

#import <Foundation/Foundation.h> 

@interface UIButton(Property) 

@property (nonatomic, retain) NSObject *property; 

@end 


UIButton+Property.m 

#import "UIButton+Property.h" 
#import <objc/runtime.h> 

@implementation UIButton(Property) 

static char UIB_PROPERTY_KEY; 

@dynamic property; 

-(void)setProperty:(NSObject *)property 
{ 
    objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

-(NSObject*)property 
{ 
    return (NSObject*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY); 
} 

@end 

// Esempio utilizzo

#import "UIButton+Property.h" 


UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
button1.property = @"HELLO"; 
NSLog(@"Property %@", button1.property); 
button1.property = nil; 
NSLog(@"Property %@", button1.property); 
+0

In che modo i riferimenti associativi sono più semplici delle estensioni di classe? – vikingosegundo

+4

Sono più puliti perché funzionano (l'estensione di classe non funziona perché l'estensione non era presente quando l'implementazione @ per la classe è stata compilata), ma questo non li rende puliti. L'aggiunta di uno stato alle classi del framework esistenti è un segno di progettazione errata e alta fragilità. Mentre la risposta di prashant funziona, fare di solito è un segno che dovresti riconsiderare la tua architettura. – bbum

+0

Non c'è bisogno di usare '@ dynamic' in quel codice, btw. – bbum

Problemi correlati