Domanda Come faccio a chiamare + metodi di classe nell'obiettivo C senza fare riferimento alla classe?


Ho una serie di oggetti "di politica" che ho ritenuto opportuno implementare come metodi di classe su un insieme di classi di criteri. Ho specificato un protocollo per questo, e ho creato classi per conformarsi a (solo uno mostrato di seguito)

@protocol Counter   
+(NSInteger) countFor: (Model *)model;
@end

@interface CurrentListCounter : NSObject <Counter> 
+(NSInteger) countFor: (Model *)model;
@end

Quindi ho una matrice delle classi che sono conformi a questo protocollo (come fa CurrentListCounter)

+(NSArray *) availableCounters {
return [[[NSArray alloc] initWithObjects: [CurrentListCounter class], [AllListsCounter class], nil] autorelease];
}

Nota come sto usando le classi come oggetti (e questo potrebbe essere il mio problema - nelle classi Smalltalk ci sono oggetti come tutto il resto - non sono sicuro che siano in Objective-C?)

Il mio problema esatto è quando voglio chiamare il metodo quando prendo uno degli oggetti della politica dall'array:

id<Counter> counter = [[MyModel availableCounters] objectAtIndex: self.index];
return [counter countFor: self];

Ricevo un avvertimento sull'istruzione return - dice -countFor: non trovato nel protocollo (quindi si presuppone che sia un metodo di istanza in cui voglio chiamare un metodo di classe). Tuttavia, poiché gli oggetti nel mio array sono istanze di classe, ora sono come i metodi di istanza (o concettualmente dovrebbero essere).

C'è un modo magico per chiamare i metodi di classe? O è solo una cattiva idea e dovrei semplicemente creare istanze dei miei oggetti della politica (e non usare i metodi di classe)?


10
2018-05-31 12:07


origine


risposte:


Questo

id <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );

Dovrebbe essere

Class <Counter> counter = [[Model availableCounters] objectAtIndex:0];
return ( [counter countFor: nil] );

Nel primo hai un'istanza conforme a <Counter>. Nel secondo hai una classe che è conforme a <Counter>. L'avviso del compilatore è corretto perché le istanze conformi a <Counter> non rispondere a countFor:, solo le classi fanno.


19
2018-06-01 09:10



Una classe in Objective-C funziona come un'istanza: la principale differenza sottostante è che il conteggio dei ritardi non fa nulla su di essi. Tuttavia, ciò che stai memorizzando nell'array -Contenitori -available non sono istanze (il id tipo) ma classi, che hanno un tipo di Class. Pertanto, con la definizione -availableCounters specificata sopra, ciò di cui hai bisogno è questo:

Class counterClass = [[MyModel availableCounters] objectAtIndex: self.index];
return ( [counterClass countFor: self] );

Tuttavia, sarebbe probabilmente semanticamente migliore se si usassero le istanze piuttosto che le classi. In tal caso, potresti fare qualcosa di simile al seguente:

@protocol Counter
- (NSUInteger) countFor: (Model *) model;
@end

@interface CurrentListCounter : NSObject<Counter>
@end

@interface SomeOtherCounter : NSObject<Counter>
@end

Quindi la classe del tuo modello potrebbe implementare quanto segue:

static NSArray * globalCounterList = nil;

+ (void) initialize
{
    if ( self != [Model class] )
        return;

    globalCounterList = [[NSArray alloc] initWithObjects: [[[CurrentListCounter alloc] init] autorelease], [[[SomeOtherCounter alloc] init] autorelease], nil];
}

+ (NSArray *) availableCounters
{
    return ( globalCounterList );
}

Quindi il tuo utilizzo sarà esattamente come hai specificato sopra:

id<Counter> counter = [[Model availableCounters] objectAtIndex: self.index];
return ( [counter countFor: self] );

5
2018-05-31 12:28



Si scopre che funziona e l'avviso non è corretto.

Quindi la domanda è ancora se sia una cosa ragionevole da fare (usare i metodi di classe se non hanno bisogno di uno stato)?

E come gestire al meglio l'avvertimento (mi piace correre senza avvertenze)?

La mia unica soluzione era di avere un secondo protocollo (essenzialmente uguale al primo ma lo dichiaro sul lato dell'istanza):

@protocol CounterInstance
-(NSInteger) countFor: (Model *)model;
@end

E dove accedo ai contatori lo uso invece (per ingannare il compilatore):

id<CounterInstance> counter = [[MyModel availableCounters] objectAtIndex: self.index];
return [counter countFor: self];

È un po 'imbarazzante, ma funziona. Sono interessato alle opinioni degli altri?


0
2018-05-31 12:25