Tworzenie klasy abstrakcyjnej w Objective-C

Jestem początkowo programistą Javy, który pracuje teraz z Objective-C. Chciałbym stworzyć klasę abstrakcyjną, ale wydaje się, że nie jest to możliwe w Objective-C. czy jest to możliwe?

Jeśli nie, jak blisko klasy abstrakcyjnej mogę dostać się w Objective-C?

Author: Peter Mortensen, 2009-06-23

21 answers

Zazwyczaj klasy Objective-C są abstrakcyjne tylko z Konwencji-jeśli autor dokumentuje klasę jako abstrakcyjną, po prostu nie używaj jej bez podklasowania jej. Nie istnieje jednak egzekwowanie czasu kompilacji, które uniemożliwia instancjację klasy abstrakcyjnej. W rzeczywistości nic nie stoi na przeszkodzie, aby Użytkownik dostarczał implementacje abstrakcyjnych metod za pomocą kategorii (np. w czasie wykonywania). Możesz zmusić użytkownika do co najmniej nadpisania niektórych metod, podnosząc wyjątek w implementacji tych metod w Twoim klasa abstrakcyjna:

[NSException raise:NSInternalInconsistencyException 
            format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];

Jeśli twoja metoda zwraca wartość, jest nieco łatwiejsza w użyciu

@throw [NSException exceptionWithName:NSInternalInconsistencyException
                               reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
                             userInfo:nil];

Ponieważ wtedy nie trzeba dodawać instrukcji return z metody.

Jeśli klasa abstrakcyjna jest rzeczywiście interfejsem (tzn. nie ma konkretnych implementacji metod), użycie protokołu Objective-C jest bardziej odpowiednią opcją.

 625
Author: Barry Wark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-11 17:43:44

Nie, Nie ma sposobu na stworzenie abstrakcyjnej klasy w Objective-C.

Możesz wyśmiewać abstrakcyjną klasę-wywołując metody / selektory doesNotRecognizeSelector: i w związku z tym podnieść wyjątek, czyniąc klasę bezużyteczną.

Na przykład:

- (id)someMethod:(SomeObject*)blah
{
     [self doesNotRecognizeSelector:_cmd];
     return nil;
}

Możesz to również zrobić dla init.

 267
Author: Grouchal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 11:30:49

Po prostu riffing na @ Barry Wark odpowiedź powyżej (i aktualizacja dla iOS 4.3) i pozostawienie tego dla mojego własnego odniesienia:

#define mustOverride() @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"%s must be overridden in a subclass/category", __PRETTY_FUNCTION__] userInfo:nil]
#define methodNotImplemented() mustOverride()

Następnie w swoich metodach możesz użyć tego

- (void) someMethod {
     mustOverride(); // or methodNotImplemented(), same thing
}



uwagi: nie jestem pewien, czy makro wygląda jak funkcja C jest dobrym pomysłem, czy nie, ale będę go trzymał do czasu, aż będzie inaczej. Myślę, że bardziej poprawne jest użycie NSInvalidArgumentException (zamiast NSInternalInconsistencyException), ponieważ to jest to, co System runtime rzuca w odpowiedzi na wywołanie doesNotRecognizeSelector (Zobacz NSObject docs).

 60
Author: Dan Rosenstark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-16 15:46:03

Rozwiązanie, które wymyśliłem to:

  1. Utwórz protokół dla wszystkiego, co chcesz w klasie "abstract"
  2. Utwórz klasę bazową (lub może nazwać ją abstrakcyjną), która implementuje protokół. Dla wszystkich metod, które chcesz "abstract" zaimplementować je w .plik m, ale nie .plik H.
  3. Niech twoja klasa potomna dziedziczy z klasy bazowej i implementuje protokół.

W ten sposób kompilator da Ci ostrzeżenie dla każdej metody w protokole, która nie jest realizowane przez twoje dziecko klasy.

Nie jest tak zwięzły jak w Javie, ale otrzymujesz żądane Ostrzeżenie kompilatora.

 41
Author: redfood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 11:33:06

Z listy dyskusyjnej grupy Omni :

Objective-C nie ma abstrakcyjnej konstrukcji kompilatora jak Java w tym razem.

Więc wszystko, co robisz, to definiujesz klasę abstrakcyjną jako każdą inną normalną klasę i zaimplementować metody dla abstrakcyjnych metod, które albo są pusty lub zgłoś brak wsparcia dla selektora. Na przykład...

- (id)someMethod:(SomeObject*)blah
{
     [self doesNotRecognizeSelector:_cmd];
     return nil;
}

Wykonuję również następujące czynności, aby zapobiec inicjalizacji abstraktu klasy poprzez domyślny inicjalizator.

- (id)init
{
     [self doesNotRecognizeSelector:_cmd];
     [self release];
     return nil;
}
 34
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 11:29:57

Zamiast tworzyć abstrakcyjną klasę bazową, rozważ użycie protokołu (podobnego do interfejsu Java). Pozwala to zdefiniować zestaw metod, a następnie zaakceptować wszystkie obiekty zgodne z protokołem i zaimplementować metody. Na przykład, mogę zdefiniować protokół operacji, a następnie mieć funkcję taką jak:

- (void)performOperation:(id<Operation>)op
{
   // do something with operation
}

Gdzie op może być dowolnym obiektem implementującym protokół operacji.

Jeśli potrzebujesz, aby Twoja abstrakcyjna klasa bazowa zrobiła coś więcej niż tylko zdefiniowała metody, możesz utworzyć zwykłą klasę Objective-C i zapobiec jej utworzeniu. Wystarczy nadpisać funkcję - (id) init i uczynić ją zwracającą nil lub assert (false). Nie jest to zbyt czyste rozwiązanie, ale ponieważ Objective-C jest w pełni dynamiczny, tak naprawdę nie ma bezpośredniego odpowiednika abstrakcyjnej klasy bazowej.

 21
Author: Ben Gotow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 19:40:30

Ten wątek jest trochę stary, a większość z tego, co chcę podzielić się jest już tutaj.

Jednak moja ulubiona metoda nie jest wymieniona, a AFAIK nie ma natywnego wsparcia w obecnym Clangu, więc idę ...

Po pierwsze, i przede wszystkim (jak już zauważyli inni) klasy abstrakcyjne są czymś bardzo rzadkim w Objective-C - zazwyczaj używamy kompozycji (czasami poprzez delegację) zamiast tego. Jest to prawdopodobnie powód, dla którego taka funkcja nie istnieje już w language / compiler-oprócz właściwości @dynamic, które IIRC zostały dodane w ObjC 2.0 towarzyszącym wprowadzeniu CoreData.

Ale biorąc to pod uwagę (po dokładnej ocenie Twojej sytuacji!) doszedłeś do wniosku, że delegacja (lub kompozycja w ogóle) nie nadaje się do rozwiązania Twojego problemu, oto jak ja to zrobić:

  1. zaimplementuj każdą abstrakcyjną metodę w klasie bazowej.
  2. Make that implementation [self doesNotRecognizeSelector:_cmd]; ...
  3. ...po którym następuje __builtin_unreachable(); aby uciszyć Ostrzeżenie, które otrzymasz za metody nie-void, mówiące "Kontrola osiągnęła koniec funkcji nie-void bez zwrotu".
  4. albo połączyć kroki 2. i 3. w makrze, lub dodać adnotację -[NSObject doesNotRecognizeSelector:] za pomocą __attribute__((__noreturn__)) w kategorii bez implementacji, aby nie zastąpić oryginalnej implementacji tej metody i dołączyć nagłówek dla tej kategorii w PCH twojego projektu.
[7]}osobiście wolę wersję makro, ponieważ pozwala mi to zmniejszyć kotłownię jako jak najbardziej.

Oto jest:

// Definition:
#define D12_ABSTRACT_METHOD {\
 [self doesNotRecognizeSelector:_cmd]; \
 __builtin_unreachable(); \
}

// Usage (assuming we were Apple, implementing the abstract base class NSString):
@implementation NSString

#pragma mark - Abstract Primitives
- (unichar)characterAtIndex:(NSUInteger)index D12_ABSTRACT_METHOD
- (NSUInteger)length D12_ABSTRACT_METHOD
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange D12_ABSTRACT_METHOD

#pragma mark - Concrete Methods
- (NSString *)substringWithRange:(NSRange)aRange
{
    if (aRange.location + aRange.length >= [self length])
        [NSException raise:NSInvalidArgumentException format:@"Range %@ exceeds the length of %@ (%lu)", NSStringFromRange(aRange), [super description], (unsigned long)[self length]];

    unichar *buffer = (unichar *)malloc(aRange.length * sizeof(unichar));
    [self getCharacters:buffer range:aRange];

    return [[[NSString alloc] initWithCharactersNoCopy:buffer length:aRange.length freeWhenDone:YES] autorelease];
}
// and so forth…

@end

Jak widać, makro zapewnia pełną implementację abstrakcyjnych metod, zmniejszając niezbędną ilość kotła do absolutnego minimum.

Jeszcze lepszą opcją byłoby lobbowanie Clang team , aby zapewnić atrybut kompilatora dla tego przypadku, za pomocą żądań funkcji. (Lepiej, ponieważ umożliwiłoby to również diagnostykę w czasie kompilacji dla tych scenariuszy, w których podklasujesz np. NSIncrementalStore.)

Dlaczego Wybieram Tą Metodę

  1. to praca wykonana sprawnie, i nieco wygodnie.
  2. To dość łatwe do zrozumienia. (OK, to __builtin_unreachable() może zaskoczyć ludzi, ale jest wystarczająco łatwe do zrozumienia, zbyt.)
  3. nie można go usunąć w release buildach bez generowania innych ostrzeżeń kompilatora lub błędów-w przeciwieństwie do podejścia opartego na jednym z makr assertion.
Ten ostatni punkt wymaga wyjaśnienia. Zgadnij:

Niektóre (większość?) ludzie rozbierają twierdzenia w release buildach. (Nie zgadzam się z tym nawykiem, ale to już inna historia...) brak wdrożenia wymaganej metody-Jednak-jest zły, straszne, źle i W zasadzie koniec wszechświata dla Twojego programu. Twój program nie może działać poprawnie w tym zakresie, ponieważ jest niezdefiniowany, a niezdefiniowane zachowanie jest najgorszą rzeczą na świecie. W związku z tym, jest w stanie rozebrać te diagnostyki bez generowania Nowa diagnostyka byłaby całkowicie nie do przyjęcia.

Jest wystarczająco źle, że nie możesz uzyskać właściwej diagnostyki w czasie kompilacji dla takich błędów programistycznych i musisz uciekać się do wykrywania w czasie uruchamiania, ale jeśli możesz to sprawdzić w release builds, po co w ogóle próbować mieć klasę abstrakcyjną?

 18
Author: danyowdee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-23 18:48:09

Użycie @property i @dynamic może również zadziałać. Jeśli zadeklarujesz właściwość dynamiczną i nie podasz implementacji dopasowującej metody, wszystko nadal będzie kompilowane bez ostrzeżeń, a otrzymasz błąd unrecognized selector podczas wykonywania, jeśli spróbujesz uzyskać do niej dostęp. Zasadniczo jest to to samo, co wywołanie [self doesNotRecognizeSelector:_cmd], ale przy znacznie mniejszym wpisywaniu.

 12
Author: Cameron Spickert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-03 21:46:31

W Xcode (używając clang itp.) lubię używać __attribute__((unavailable(...))) do oznaczania klas abstrakcyjnych, aby uzyskać błąd / ostrzeżenie, jeśli spróbujesz go użyć.

Zapewnia pewną ochronę przed przypadkowym użyciem metody.

Przykład

W klasie bazowej @interface Oznacz metody "abstrakcyjne":

- (void)myAbstractMethod:(id)param1 __attribute__((unavailable("You should always override this")));

Idąc o krok dalej, tworzę makro:

#define UnavailableMacro(msg) __attribute__((unavailable(msg)))

To pozwala ci to zrobić:

- (void)myAbstractMethod:(id)param1 UnavailableMacro(@"You should always override this");

Jak mówiłem, nie jest to prawdziwa ochrona kompilatora, ale jest tak dobra jak masz zamiar dostać się w języku, który nie obsługuje abstrakcyjnych metod.

 7
Author: rjstelling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-06 02:05:36

ODPOWIEDŹ na pytanie jest rozrzucona w komentarzach pod już udzielonymi odpowiedziami. Tak więc, ja tylko streszczam i upraszczam tutaj.

Option1: Protokoły

Jeśli chcesz utworzyć abstrakcyjną klasę bez implementacji, użyj 'Protocols'. Klasy dziedziczące protokół są zobowiązane do implementacji metod w protokole.

@protocol ProtocolName
// list of methods and properties
@end

Option2: Wzór Metody Szablonu

Jeśli chcesz utworzyć abstrakcyjną klasę z częściową implementacją jak "Szablon metoda wzór" to jest rozwiązanie. Objective-C - szablon metody wzór?

 7
Author: hadaytullah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:33

Inna alternatywa

Po prostu sprawdź klasę w klasie abstrakcyjnej i Potwierdź lub wyjątek, cokolwiek chcesz.

@implementation Orange
- (instancetype)init
{
    self = [super init];
    NSAssert([self class] != [Orange class], @"This is an abstract class");
    if (self) {
    }
    return self;
}
@end

Usuwa to konieczność nadpisania init

 6
Author: bigkm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-17 21:50:37

(bardziej pokrewna sugestia)

Chciałem mieć sposób na poinformowanie programisty "nie dzwoń od dziecka" i całkowite nadpisanie (w moim przypadku nadal oferują domyślną funkcjonalność w imieniu rodzica, gdy nie jest rozszerzona): {]}

typedef void override_void;
typedef id override_id;

@implementation myBaseClass

// some limited default behavior (undesired by subclasses)
- (override_void) doSomething;
- (override_id) makeSomeObject;

// some internally required default behavior
- (void) doesSomethingImportant;

@end

Zaletą jest to, że programista zobaczy "override" w deklaracji i będzie wiedział, że nie powinien wywoływać [super ..].

Przyznaję, brzydkie jest definiowanie poszczególnych typów zwrotów, ale służy jako wystarczająco dobra podpowiedź wizualna i łatwo nie możesz użyć części "override_" w definicji podklasy.

Oczywiście klasa może nadal mieć domyślną implementację, gdy rozszerzenie jest opcjonalne. Ale jak mówią inne odpowiedzi, zaimplementuj wyjątek run-time, gdy jest to właściwe, jak w przypadku klas abstrakcyjnych (wirtualnych).

Byłoby miło mieć wbudowane podpowiedzi kompilatora, takie jak ten, nawet podpowiedzi, kiedy najlepiej jest pre / post wywołać implementację super, zamiast kopać przez komentarze / dokumentacja lub... Załóżmy.

przykład podpowiedzi

 5
Author: Ivan Dossev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-04 15:25:48

Jeśli jesteś przyzwyczajony do tego, że kompilator łapie abstrakcyjne instancje w innych językach, to zachowanie Objective-C jest rozczarowujące.

Jako język późnego wiązania jest jasne, że Objective-C nie może podejmować statycznych decyzji o tym, czy klasa jest naprawdę abstrakcyjna, czy nie (możesz dodawać funkcje w czasie wykonywania...), ale dla typowych przypadków użycia wydaje się to wadą. Wolałbym, aby kompilator blokował instancje klas abstrakcyjnych zamiast rzucać błąd podczas wykonywania.

Oto wzór, którego używamy do uzyskania tego typu sprawdzania statycznego za pomocą kilku technik ukrywania inicjalizatorów:

//
//  Base.h
#define UNAVAILABLE __attribute__((unavailable("Default initializer not available.")));

@protocol MyProtocol <NSObject>
-(void) dependentFunction;
@end

@interface Base : NSObject {
    @protected
    __weak id<MyProtocol> _protocolHelper; // Weak to prevent retain cycles!
}

- (instancetype) init UNAVAILABLE; // Prevent the user from calling this
- (void) doStuffUsingDependentFunction;
@end

//
//  Base.m
#import "Base.h"

// We know that Base has a hidden initializer method.
// Declare it here for readability.
@interface Base (Private)
- (instancetype)initFromDerived;
@end

@implementation Base
- (instancetype)initFromDerived {
    // It is unlikely that this becomes incorrect, but assert
    // just in case.
    NSAssert(![self isMemberOfClass:[Base class]],
             @"To be called only from derived classes!");
    self = [super init];
    return self;
}

- (void) doStuffUsingDependentFunction {
    [_protocolHelper dependentFunction]; // Use it
}
@end

//
//  Derived.h
#import "Base.h"

@interface Derived : Base
-(instancetype) initDerived; // We cannot use init here :(
@end

//
//  Derived.m
#import "Derived.h"

// We know that Base has a hidden initializer method.
// Declare it here.
@interface Base (Private)
- (instancetype) initFromDerived;
@end

// Privately inherit protocol
@interface Derived () <MyProtocol>
@end

@implementation Derived
-(instancetype) initDerived {
    self= [super initFromDerived];
    if (self) {
        self->_protocolHelper= self;
    }
    return self;
}

// Implement the missing function
-(void)dependentFunction {
}
@end
 4
Author: Cross_,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 11:43:17

Prawdopodobnie tego typu sytuacje powinny mieć miejsce tylko w czasie rozwoju, więc to może zadziałać:

- (id)myMethodWithVar:(id)var {
   NSAssert(NO, @"You most override myMethodWithVar:");
   return nil;
}
 3
Author: juanjo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-26 03:27:56

Możesz użyć metody zaproponowanej przez @Yar (z pewną modyfikacją):

#define mustOverride() @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"%s must be overridden in a subclass/category", __PRETTY_FUNCTION__] userInfo:nil]
#define setMustOverride() NSLog(@"%@ - method not implemented", NSStringFromClass([self class])); mustOverride()

Tutaj otrzymasz wiadomość typu:

<Date> ProjectName[7921:1967092] <Class where method not implemented> - method not implemented
<Date> ProjectName[7921:1967092] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[<Base class (if inherited or same if not> <Method name>] must be overridden in a subclass/category'

Lub twierdzenie:

NSAssert(![self respondsToSelector:@selector(<MethodName>)], @"Not implemented");

W tym przypadku otrzymasz:

<Date> ProjectName[7926:1967491] *** Assertion failure in -[<Class Name> <Method name>], /Users/kirill/Documents/Projects/root/<ProjectName> Services/Classes/ViewControllers/YourClass:53

Można też korzystać z protokołów i innych rozwiązań - ale to jedno z najprostszych.

 3
Author: gbk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 11:44:18

Kakao nie dostarcza niczego, co nazywa się abstrakcją. Możemy utworzyć abstrakcję klasy, która jest sprawdzana tylko w czasie wykonywania, a w czasie kompilacji nie jest sprawdzana.

 2
Author: Hussain Shabbir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 11:36:20

Zwykle wyłączam metodę init w klasie, którą chcę abstrakcyjnie:

- (instancetype)__unavailable init; // This is an abstract class.

Spowoduje to wygenerowanie błędu podczas kompilacji za każdym razem, gdy wywołasz init na tej klasie. Następnie używam metod klasowych do wszystkiego innego.

Objective-C nie ma wbudowanego sposobu deklarowania klas abstrakcyjnych.

 1
Author: Mahouk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-20 11:09:27

Zmieniając trochę to, co @ redfood zasugerował stosując komentarz @ dotToString, masz rozwiązanie przyjęte przez Instagram ' s IGListKit .

  1. Utwórz protokół dla wszystkich metod, które nie mają sensu definiować w klasie bazowej (abstrakcyjnej), tzn. potrzebują konkretnych implementacji w dzieciach.
  2. Utwórz klasę bazową (abstrakcyjną), która nie implementuje tego protokołu. Możesz dodać do tej klasy inne metody, które mają sens mają wspólną realizację.
  3. wszędzie w Twoim projekcie, jeśli potomek z AbstractClass musi być wprowadzany lub wyprowadzany przez jakąś metodę, wpisz go jako AbstractClass<Protocol>.

Ponieważ AbstractClass nie implementuje Protocol, jedynym sposobem na posiadanie instancji AbstractClass<Protocol> jest podklasowanie. Ponieważ sama AbstractClass nie może być używana nigdzie w projekcie, staje się abstrakcyjna.

Oczywiście, nie uniemożliwia to niewskazanym programistom dodawania nowych metod odnoszących się po prostu do AbstractClass, co ostatecznie pozwoli instancja (już nie) klasy abstrakcyjnej.

Przykład ze świata rzeczywistego: IGListKit ma klasę bazową IGListSectionController, która nie implementuje protokołu IGListSectionType, jednak każda metoda, która wymaga instancji tej klasy, w rzeczywistości pyta o Typ IGListSectionController<IGListSectionType>. Dlatego nie ma sposobu na użycie obiektu typu IGListSectionController do czegokolwiek użytecznego w ich ramach.

 0
Author: Gobe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-18 17:24:43

W rzeczywistości Objective-C nie ma klas abstrakcyjnych, ale możesz użyć protokołów , aby osiągnąć ten sam efekt. Oto przykład:

CustomProtocol.h

#import <Foundation/Foundation.h>

@protocol CustomProtocol <NSObject>
@required
- (void)methodA;
@optional
- (void)methodB;
@end

TestProtocol.h

#import <Foundation/Foundation.h>
#import "CustomProtocol.h"

@interface TestProtocol : NSObject <CustomProtocol>

@end

TestProtocol.m

#import "TestProtocol.h"

@implementation TestProtocol

- (void)methodA
{
  NSLog(@"methodA...");
}

- (void)methodB
{
  NSLog(@"methodB...");
}
@end
 0
Author: york,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 11:34:52

Prosty przykład tworzenia klasy abstrakcyjnej

// Declare a protocol
@protocol AbcProtocol <NSObject>

-(void)fnOne;
-(void)fnTwo;

@optional

-(void)fnThree;

@end

// Abstract class
@interface AbstractAbc : NSObject<AbcProtocol>

@end

@implementation AbstractAbc

-(id)init{
    self = [super init];
    if (self) {
    }
    return self;
}

-(void)fnOne{
// Code
}

-(void)fnTwo{
// Code
}

@end

// Implementation class
@interface ImpAbc : AbstractAbc

@end

@implementation ImpAbc

-(id)init{
    self = [super init];
    if (self) {
    }
    return self;
}

// You may override it    
-(void)fnOne{
// Code
}
// You may override it
-(void)fnTwo{
// Code
}

-(void)fnThree{
// Code
}

@end
 0
Author: Say2Manuj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-25 19:21:04

Nie możesz po prostu utworzyć delegata?

Delegat jest jak abstrakcyjna klasa bazowa w tym sensie, że mówisz, jakie funkcje należy zdefiniować, ale nie definiujesz ich.

Wtedy za każdym razem, gdy implementujesz swojego delegata (np. klasę abstrakcyjną), kompilator ostrzega cię, jakie funkcje opcjonalne i obowiązkowe są potrzebne do zdefiniowania zachowania.

To brzmi jak abstrakcyjna klasa bazowa.

 -3
Author: user1709076,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-22 14:09:22