Mischen von C-Funktionen in einer Objective-C-Klasse
Lesezeit: 5 Minuten
Richard Stelling
Ich schreibe eine Objective-C-Klasse, aber sie verwendet eine in C geschriebene API. Dies ist meistens in Ordnung, da das Mischen von C-Aufrufen mit Objective-C-Aufrufen nur wenige Probleme verursacht.
Einer der API-Aufrufe erfordert jedoch eine Rückrufmethode (Beispiel):
Kann/wie kann ich stattdessen eine Objective-C-Methode aufrufen?
Kann/sollte ich C-Funktionen mit meinen Objective-C-Aufrufen mischen?
Wie mische ich C-Funktionen mit Objective-C-Methoden?
Richard Stelling
Das Mischen von C- und Objective-C-Methoden und -Funktionen ist möglich, hier ist ein einfaches Beispiel, das die SQLite-API in einer iPhone-App verwendet: (Kursseite)
C-Funktionen müssen außerhalb deklariert werden @implementation in einer Objective-C-Datei (.m).
int MyCFunction(int num, void *data)
{
//code here...
}
@implementation
- (void)MyObjectiveCMethod:(int)number withData:(NSData *)data
{
//code here
}
@end
Da die C-Funktion außerhalb von liegt @implementation es kann keine Methoden wie aufrufen
[self doSomething]
und hat keinen Zugriff auf Ivars.
Dies kann umgangen werden, solange die Rückruffunktion eine dauert userInfo oder context Typparameter, normalerweise vom Typ void*. Dies kann verwendet werden, um jedes Objective-C-Objekt an die C-Funktion zu senden.
Wie im Beispielcodekann dies mit normalen Objective-C-Operationen manipuliert werden.
Lesen Sie außerdem diese Antwort: Mischen von C-Funktionen in einer Objective-C-Klasse
C-Funktionen müssen nicht außerhalb liegen @implementation.
– Benutzer557219
17. April 2011 um 12:11 Uhr
@Bavarous: Der Compiler lässt Sie mit Funktionen im Inneren davonkommen @implementationaber es ist immer noch nicht Teil der @implementation, da Funktionen nicht zu einer Klasse gehören können. Aus Stilgründen lasse ich es außen vor @implementationund empfehlen Sie anderen, dasselbe zu tun, um dies deutlich zu machen.
– Peter Hosey
1. Dezember 2011 um 23:32 Uhr
Tatsächlich haben C-Funktionen innerhalb von @implementation-Blöcken die einzigartige Eigenschaft, direkt auf private und geschützte ivars zugreifen zu können. Aus meiner eigenen Erfahrung ist es daher zu einer starken Redewendung geworden, C-Funktionen, die zu einer Klasse “gehören”, innerhalb der entsprechenden Implementierung zu platzieren. Ich würde empfehlen, Ihre Antwort zu aktualisieren.
– Josh Rosen
2. Dezember 2011 um 0:00 Uhr
Zur Verdeutlichung haben sie Zugriff auf private Ivars, wenn sie Zugriff auf eine Instanz der Klasse erhalten. ZB int MyCFunction(MyClass* self, int num, void *data). Dies ähnelt sehr dem, was hinter den Kulissen vor sich geht, wenn Ihre -MyObjectiveCMethod:withData: objc-Methode kompiliert wird.
– Josh Rosen
2. Dezember 2011 um 0:13 Uhr
c-Funktionen können tatsächlich auch innerhalb des Implementierungsbereichs definiert werden, und niemand würde sich beschweren. Und sie können auf keinen Fall innerhalb oder außerhalb der @-Implementierung auf self zugreifen, einfach weil sie keine Methoden des Objekts sind.
– Matteo Gobbi
30. Januar 2019 um 22:20 Uhr
Um Objective-C-Code von einem C-Callback aufzurufen, würde ich so etwas verwenden:
Nur eine Ergänzung: Viele Callbacks erlauben die Angabe von “Benutzerdaten”; In diesem Fall könnte der Objektzeiger als Benutzerdaten verwendet werden (und Sie brauchen die globale Variable refToSelf nicht mehr). Es kann sein, dass Ihre Callback-Funktion “Benutzerdaten” im Info-Zeiger unterstützt.
– Aschefang
29. April 2009 um 12:38 Uhr
Ich erhalte Warnungen zu einem Speicherleck zur Laufzeit, wenn ARC mit dem obigen Code aktiviert ist. stackoverflow.com/questions/11840943/…
– docchang
7. August 2012 um 7:13 Uhr
Dies ist eine fehlerhafte Implementierung. Es wird davon ausgegangen, dass Sie nur eine Instanz von ComeClass haben. void *refToSelf; ist eine statische/globale Variable. Jedes Mal, wenn Sie [[SomeClass alloc] init]wird Ihr refToSelf von der zuletzt erstellten Instanz überschrieben. Der cCallback ruft NICHT die richtige SomeClass auf, sondern immer die zuletzt erstellte. Darüber hinaus stürzt es ab, wenn die zuletzt erstellte SomeClass freigegeben wird (zumindest im obigen Code), da Sie refToSelf beim Dealloc der SomeClass nicht löschen.
– Motti Schoner
3. Dezember 2014 um 10:22 Uhr
Um das zu ergänzen, was @ashcatch gesagt hat: Wenn Ihr Rückruf a gegeben wird void *userDatastellen Sie sicher, dass Sie es in einen Zeiger auf Ihre Objective-C-Klasseninstanz mit umwandeln (__bridge id)(userData) Warnungen und Lecks zu vermeiden.
– VinceFior
12. Juli 2015 um 8:45 Uhr
Wenn eine Klasse Singleton ist, ist dies in Ordnung. aber es ist kein Singleton, stimme der Antwort von @MottiShneor zu.
– damithH
7. Dezember 2015 um 4:23 Uhr
Peter Hosey
Kann/wie kann ich stattdessen eine Objective-C-Methode aufrufen?
Sie können nicht.
Kann/sollte ich die C-Funktion mit meinem Objective-C-Aufruf mischen?
Ja. Schreiben Sie eine C-Funktion und verwenden Sie diese als Callback für die CF-Funktion.
Wie mische ich C-Funktionen mit Objective-C-Methoden?
Sie können einstellen self als die info Zeiger in Ihrer Kontextstruktur. Das wird an den Callback weitergegeben. Setzen Sie dann im Rückruf die info Zeiger zurück zu id:
MyClass *self = (id)info;
Sie können dann senden self Mitteilungen. Sie können jedoch immer noch nicht direkt auf Instanzvariablen zugreifen, da sich eine C-Funktion außerhalb von befindet @implementation Sektion. Sie müssen sie zu Eigenschaften machen. Sie können dies mit einem tun Klassenerweiterung. (Im Gegensatz zu dem, was dieses Dokument sagt, würden Sie die Erweiterung nicht darin deklarieren @implementationaber in derselben Datei damit, im Allgemeinen direkt darüber.)
Was ich in dieser Situation immer als hilfreich empfunden habe, ist, einen Obj-C-Wrapper auf der C-API zu erstellen. Implementieren Sie, was Sie für die Verwendung von C-Funktionen benötigen, und bauen Sie eine Objective-C-Klasse (oder zwei) darauf auf, damit die Außenwelt nichts davon sieht. Im Falle eines Rückrufs wie diesem könnten Sie beispielsweise eine C-Funktion erstellen, die Obj-C-Delegatmethoden für andere Objekte aufruft.