2010-03-01 12 views
5

Das ist eine Art Anfängerfrage, also bitte mit mir ertragen.Ist es möglich, "Nur-Implementierungs" -Klassenmitglieder zu haben?

Ich habe eine Klasse, die eine Bibliothek von Drittanbietern verwendet (Oniguruma, wenn das wichtig ist). Ich möchte, dass Bibliotheksmethoden vollständig von mir selbst gestaltet werden, sodass ich jederzeit die zugrunde liegende Implementierung meiner Klasse wechseln kann. Etwas wie:

// MyClass.h 

@interface MyClass : NSObject ... 

- (int) doSomething; 


// MyClass.m 

#import "some_library.h" 

@implementation MyClass 

- (int) doSomething 
{ 
    //call library's specific stuff 
} 

So weit, so gut, aber jetzt bin ich um eine Instanzvariable in MyClass zu verwenden, die eine Bibliothek definierten Art hat (eine Struktur erklärt in „some_library.h“). Natürlich kann ich die Bibliothek direkt im Interface-Abschnitt importieren:

//MyClass.h 

#import "some_library.h" 

@interface MyClass : NSObject { 
    some_library_t blah; 
} 
- (int) doSomething; 
@end 

aber das ist genau das, was ich zu vermeiden, bin versucht - sich seine Implementierungsdetails machen Nutzer von MyClass.

Kann ich bibliothekspezifische Typen irgendwie von der Schnittstelle meiner Klasse "verstecken"? Was ist die Standardpraxis?

Antwort

8

Die gängige Praxis ist opaque pointers entweder auf die Bibliothekstypen zu verwenden oder eine benutzerdefinierte Implementierung Struktur (also seine auch Pimpl genannt-Zeiger auf Implementierung).

Um das zu tun, müssen Sie wissen, dass Sie Zeiger auf unvollständige Typen definieren können, d. H. Typen, die Sie nur als existent deklarieren. Z.B .:

struct FooImpl; 

@interface Foo { 
    struct FooImpl* impl; // using pointer is ok for incomplete types 
}   
@end 

Sie dann den Typ in der Implementierungsdatei definieren:

struct FooImpl { 
    // ... member definition 
}; 

und zuteilen/initialisieren es z.B. in Ihrer -(id)init Methode.

FooImpl könnte auch SomeLibraryType sein, wenn der Bibliothekstyp eine Struktur wäre - dann würden Sie sie auf die gleiche Weise weiterleiten und den Bibliothekskopf in die Quelldatei einschließen, was Ihnen die Strukturdefinition gibt.

+0

Meine schlecht, festgelegt. Ich habe mich zu sehr an C++ gewöhnt, um 'struct' zu verwenden. –

3

gfs Antwort ist tot, aber es gibt auch einen anderen Weg. Verwenden Sie eine undurchsichtige Klasse.

foo.h:

@interface Foo : NSObject 
{ 
    id internalGunk; 
} 
@end 

Foo.m:

#import "Foo.h" 

@interface PrivateStuff:NSObject 
... declare ivars and/or properties and/or methods here ... 
@end 

@implementation PrivateStuff 
... any custom implementation and/or @synthesizes here ... 
@end 

#define SELF_PRIVVY ((PrivateStuff *)internalGunk) 
@implementation Foo 
... implementation here ... 
@end 

Wenn Sie SELF_PRIVVY nicht mögen, dann können Sie etwas tun:

// in Foo's @implementation 
- (PrivateStuff *) privateStuff { return internalGunk; } 

Die über dem Muster (alles) hat ein paar Vorteile. Erstens ist es vollständig kompatibel mit GC, da alles als Objektreferenzen deklariert ist. Zweitens ist es viel einfacher, das private Zeug bei Bedarf in eine separate Klasse umzuformen. Schließlich macht es diese Klasse leichter, die Privaten zu halten, um jegliche Logik oder Persistenz in Bezug auf diese privaten Dinge von allem anderen zu trennen; Es erleichtert zukünftiges Refactoring.

Ob es eine bessere Lösung für Ihre Bedürfnisse ist, hängt von Ihren spezifischen Anforderungen ab.

0

ich gelesen, dass da LLVM 3.0 können Sie die geschweiften Klammern Schnitt der Schnittstelle bewegen (die die ivars erklärt) zur Umsetzung (.m-Datei, innerhalb @implementation Block)

Quelle: http://www.raywenderlich.com/5773/beginning-arc-in-ios-5-tutorial-part-2

(Der Link ist ein ARC-Tutorial, aber diese neue Funktion ist unabhängig von ARC).

Persönlich bin ich sowohl erstaunt und glücklich.

EDIT: Es stellt sich heraus, es ist da Xcode 4.2:

What's the difference between adding pseudo-private ivars in a class extension or in the @implementation block?

Verwandte Themen