2012-07-18 17 views
51

ObjectProperties.hCel C Protokół przodu Zgłoszenia

@protocol ObjectProperties <NSObject> 

@property (strong, nonatomic) NSString *name; 
@property (strong, nonatomic) NSDate *date; 
@property (assign, nonatomic) int64_t index; 

@end 

ClassA.h

#import <Foundation/Foundation.h> 

@protocol ObjectProperties; 

@interface ClassA : NSObject <ObjectProperties> 

- (void)specialSauce; 

@end; 

ManagedClassA.h

#import <CoreData/CoreData.h> 

@protocol ObjectProperties; 

@interface ManagedClassA : NSManagedObject <ObjectProperties> 

- (void)doSomething; 

@end; 

Z powyższego przykładu kodu zdefiniowałem protokół w pliku .h do użycia zarówno z obiektami Core Data, jak i zwykłymi obiektami waniliowymi. Wygląda na to, że "hałas" ma zgodne klasy: #importuj protokół w ich nagłówku; Byłoby czystsze przekazywać dalej deklarowanie importu w pliku implementacji, jak pokazano powyżej. Jednak Xcode generuje ostrzeżenie, gdy robi to w ten sposób:

Cannot find protocol definition for 'ObjectProperties'

Kod kompiluje, a przede wszystkim działa. Mówię głównie dlatego, że z Core Data próbuje się dynamicznie tworzyć metody pobierające/ustawiające dla właściwości skalarnej, ale myślę, że to pewnie dlatego, że trafiłem na przypadek skrajny.

Oczywiście najbardziej oczywistym zadaniem jest zaimportowanie nagłówka protokołu do nagłówków klas.

Jeśli moje zrozumienie jest poprawne (a moja wiedza została niedawno nabyta, a więc jest całkowicie możliwe, że się mylę), jeśli zaimportuję protokół do nagłówków mojej klasy i wprowadzę zmianę do protokołu, wówczas wszystkie kolejne pliki importujące moje klasy będą musiały zostać ponownie skompilowane.

Jaki jest prawidłowy sposób rozwiązania tego typu problemu?

+0

Mam podobny problem, ale z protokołem Swift. – Alper

Odpowiedz

93

Nie możesz przodu zadeklarować superklasę lub protokół, który jest zgodny. W takich przypadkach należy podać nagłówek.Dzieje się tak, ponieważ (w przypadku superklasy) zmienne i metody instancji nadklasy stają się częścią twojej klasy; lub (w przypadku protokołów) metody protokołu stają się metodami zadeklarowanymi w klasie, bez konieczności zadeklarowania ich jawnie. (Teraz inne osoby, które zawierają nagłówek twojej klasy, zobaczą, że twoja klasa deklaruje te metody, tak jakbyś je sam zadeklarował.) Jedynym sposobem, który może być możliwy, jest to, że zostały już zdefiniowane w tym zakresie, tzn. ich nagłówki są importowane .

#import <SomeClass.h> 
#import <SomeProtocol.h> // these two must be imported 

@interface MyClass : SomeClass <SomeProtocol> 
@end 

Deklaracje przekazywania są użyteczne w przypadku rzeczy, które pojawiają się tylko w typie zmiennej (w szczególności zmiennej wskaźnika obiektu). Wskaźniki obiektów są tego samego rozmiaru i nie ma różnicy między różnymi typami wskaźników obiektów w czasie wykonywania (pojęcie typu wskaźnika obiektu jest tylko kwestią czasu kompilacji). Tak więc nie ma prawdziwej potrzeby, aby dokładnie wiedzieć, co jest w klasach tego typu. W ten sposób mogą być zadeklarowane do przodu.

@class SomeClass; 
@protocol SomeProtocol; // you can forward-declare these 

@interface MyClass { 
    SomeClass *var1; 
    id<SomeProtocol> var2; 
} 
@end 
4

Tak, masz rację, że wszystkie pliki będą wymagały ponownej kompilacji, ale jest to konieczne. Pliki importujące nagłówek klasy muszą znać metody związane z wdrażanym protokołem. Jeśli ukryjesz tę definicję w pliku .m, będzie ona widoczna tylko dla jednego pliku (ponieważ pliki .m nigdy nie zostaną zaimportowane). To nie to samo, co deklarujące klasy. Jeśli przekazujesz dalej deklarację protokołu, musisz zadeklarować ją gdzieś, która jest widoczna w tym samym zakresie co deklaracja przekazania. Nie mogę wymyślić żadnego przykładu, w którym to nie występuje w tym samym pliku.

W ARC to błąd, ponieważ ARC musi wiedzieć o zarządzaniu pamięcią zadeklarowanych metod (czy wrócą +1 instancje, wskaźniki wewnętrzne, itp?)

2

Deklarując swoją klasę w MyClass.h , musisz zaimportować wszystkie pliki nagłówkowe dla swojej nadklasy, jak również protokoły przyjęte w pliku MyClass.h. Protokoły w Objective-c są uważane za wariant dziedziczenia.

Deklaracje forward są zwykle używane w deklaracji członkowskiej klasy.

1

Ponieważ deklarujesz zgodność z protokołem, powinieneś #poprzekazać nagłówek zawierający protokół.

To jest taka sama jak #importing superklasy, zamiast do przodu deklarowania go:

@class Foo; 

@interface Bar : Foo 
// Will get error: attempting to use the forward class 'Foo' as superclass of 'Bar' 
@end;