Für diejenigen, die meine Vernunft / Zeitverschwendung / Fähigkeit / Motive in Frage stellen, ist dieses Ding ein Port des " Foundation mit einem Löffel " Projekt, jetzt berüchtigt für eine All-C-iOS-App.
Also, ich habe eine c-Datei auf den Markt gebracht, die die Haupt-Klasse hinter einer all-C-Mac-App ist, jedoch verhindert eine Kombination von einschränkenden Faktoren, dass die Anwendung gestartet wird. Wie es derzeit ist, ist das Projekt nur eine main.m und eine Klasse namens AppDelegate.c, also habe ich "AppDelegate" als Name der Hauptklasse in der info.plist eingegeben, und zu meiner völligen Überraschung, das Protokoll gedruckt:
Klasse kann nicht gefunden werden: AppDelegate, Beenden
Dies würde in iOS perfekt funktionieren, da die Hauptfunktion den Namen einer Delegatklasse akzeptiert und automatisch verarbeitet, aber NSApplicationMain () kein solches Argument akzeptiert.
Nun, ich weiß, dass dies auf die Tatsache zurückzuführen ist, dass es keine @interface/@implementation
Direktiven in C gibt, und genau das scheint das Betriebssystem zu suchen, also schrieb ich eine einfache NSApplication
Unterklasse und stellte sie als Principal zur Verfügung Class to the Plist, und es startete perfekt gut. Meine Frage ist, wie könnte man eine c-Datei als Hauptklasse in einer Mac-Anwendung einstellen und sie korrekt starten lassen?
BEARBEITEN: Gelöst! Die Datei kann eine .m (Framework-Fehler, aus irgendeinem Grund) sein, aber die Zuordnung von Klassenpaaren ist genug, um vorbei zu gehen. Sie können die Quelle für die C-basierte Mac App hier herunterladen . Glückliches Graben!
Der Code wurde geschrieben, signiert, versiegelt und gestempelt, aber alles, was ich brauche, ist ein Weg um die NSPrincipalClass-Anforderung im plist.
Okay, hier ist eine substantiell umgeschriebene Antwort, die zu funktionieren scheint ich.
Ihre Probleme sind also ziemlich unabhängig von der Hauptklasse. Sie
sollte die Hauptklasse als NSApplication
belassen.
Das Hauptproblem, auf das ich bereits hingewiesen habe, ist, dass Sie keine registrieren geeignete Anwendungsdelegate mit NSApplication. Wechseln Hauptklasse wird das nicht beheben. Eine NIB-Datei kann die Anwendung festlegen delegieren, aber das ist wirklich übertrieben für dieses Problem.
Allerdings gibt es tatsächlich mehrere Probleme:
Ihr (geposteter) Code wird mit einigen iOS Klassen und Methoden geschrieben passen nicht ganz zu den OS X-Versionen.
Sie müssen sicherstellen, dass Ihre AppDelegate-Klasse registriert ist das System, und dann müssen Sie NSApplication manuell initialisieren und Legen Sie den Anwendungsdelegierten fest.
Die Verknüpfung ist hier sehr sehr wichtig. Du brauchst
habe ein externes Symbol, das den Linker dazu bringt, das Foundation-Kit zu ziehen
und das AppKit in den Speicher. Ansonsten gibt es keine einfache Möglichkeit, sich zu registrieren
Klassen wie NSObject
mit der Objective-C-Laufzeit.
OSX-Anwendungsdelegaten stammen von NSObject
, nicht von
UIResponder
, also die Zeile:
sollte lauten:
%Vor% Außerdem antworten die Delegierten der OSX-Anwendung auf andere Nachrichten als die Delegierten der iOS-Anwendung. Insbesondere müssen sie auf den applicationDidFinishLaunching:
Selektor antworten (der ein NSNotifier
Objekt vom Typ id
benötigt).
Die Zeile
%Vor%sollte lauten:
%Vor% Beachten Sie, dass die Parameter ( "i@:@@"
und "i@:@"
) unterschiedlich sind.
Es gibt zwei Möglichkeiten, um AppDelegate
mit der Objective-C-Laufzeit zu registrieren:
Deklarieren Sie Ihre initAppDel
-Methode mit __attribute__((constructor))
,
Dadurch wird er vom Setup-Code vor main
oder
Rufen Sie sich selbst an, bevor Sie das Objekt instanziieren.
Ich vertraue generell __attribute__
labels nicht. Sie werden wahrscheinlich gleich bleiben, aber Apple könnte sie ändern. Ich habe gewählt, dass initAppDel
von main
aufgerufen wird.
Sobald Sie Ihre AppDelegate
-Klasse mit dem System registriert haben, ist es im Grunde genommen
funktioniert wie eine Objective-C-Klasse. Sie instanziieren es wie eine Objective-C-Klasse, und Sie können es wie ein id
weitergeben. Es ist tatsächlich ein id
.
Um sicherzustellen, dass AppDelegate als Anwendungsdelegat ausgeführt wird, müssen Sie NSAppliction
einrichten. Da Sie Ihren eigenen Anwendungsdelegaten ausführen, können Sie wirklich NSApplicationMain
nicht dazu verwenden. Es stellte sich heraus, dass es nicht so schwer war:
Also, hier ist das wahre Fleisch des Problems, zumindest für mich. Alle der
oben wird ganz und gar versagen, es sei denn, du hast es tatsächlich getan
NSObject
und NSApplication
wurden in der Objective-C-Laufzeit registriert.
Normalerweise, wenn Sie in Objective-C arbeiten, teilt der Compiler dem Linker mit
dass es das braucht. Es tut dies, indem es ein Bündel von speziellen setzt
ungelöste Symbole in der Datei .o
. Wenn ich die Datei SomeObj.m kompiliere:
Verwenden Sie clang -c SomeObj.m
, und sehen Sie sich dann die Symbole mit nm SomeObj.o
an:
Sie sehen all diese netten _OBJC_CLASS_$_
Symbole mit einem U
an
Die linke zeigt an, dass die Symbole nicht aufgelöst sind. Wenn Sie verlinken
Diese Datei nimmt der Linker und stellt fest, dass er geladen werden muss
der Rahmen der Stiftung, um die Referenzen zu lösen. Dies zwingt die
Foundation Framework, um alle seine Klassen mit dem Objective-C zu registrieren
Laufzeit. Etwas ähnliches ist erforderlich, wenn Ihr Code das AppKit benötigt
Rahmen.
Wenn ich Ihren AppDelegate-Code kompiliere, den ich umbenannt habe
'AppDelegate_orig.c' mit clang -c AppDelegate_orig.c
und dann ausführen
nm
darauf:
Sie werden sehen, dass es keine ungelösten Symbole gibt, die das erzwingen würden
Foundation- oder AppKit-Frameworks zum Verknüpfen. Dies bedeutet, dass alle meine Anrufe
to objc_getClass
würde NULL zurückgeben, was bedeutet, dass die ganze Sache
kommt zusammenbrechen.
Ich weiß nicht, wie der Rest Ihres Codes aussieht, also kann das nicht sein ein Problem für Sie, aber das Lösen dieses Problems ließ mich eine modifizierte kompilieren AppDelegate.c-Datei von selbst in ein (nicht sehr funktionelles) OSX Anwendung.
Das Geheimnis hier ist, ein externes Symbol zu finden, das den Linker benötigt
Foundation und AppKit einbringen. Das stellte sich als relativ heraus
einfach. Das AppKit stellt eine globale Variable NSApp
zur Verfügung, die den
Anwendungsinstanz von NSApplication
. Das AppKit-Framework beruht darauf
auf dem Foundation Framework, also bekommen wir das kostenlos. Einfach erklären
ein externer Hinweis darauf war genug:
(NB: Sie müssen die Variable irgendwo benutzen, oder den Compiler kann es optimieren, und Sie werden die Frameworks verlieren, die Sie benötigen.)
Hier ist meine Version von AppDelegate.c. Es enthält main
und sollte gesetzt werden
alles auf.Das Ergebnis ist nicht so aufregend, aber es öffnet sich ein
kleines Fenster auf dem Bildschirm.
Kompilieren, installieren und ausführen wie folgt:
%Vor%Info.plist ist:
%Vor%Mit einem Screenshot:
Auf diesem Weg liegt der Wahnsinn oder zumindest eine große Zeitverschwendung. Cocoa-Apps sind inhärent auf Objective-C-Basis entworfen und verwenden einen .app-Wrapper mit einer Unterverzeichnishierarchie von sehr spezifischem Design (einschließlich der Anforderung von Dingen wie Info.plist und möglicherweise Codesignatur).
Die Delegiertenfrage, in die Sie hineingeraten sind, ist nur ein Ablenkungsmanöver; Das eigentliche Problem ist, dass Sie nicht wirklich eine richtige Cocoa-App erstellen.
Und nein, es würde unter iOS nicht perfekt funktionieren, weil diese Plattform, noch mehr, erfordert, dass die Anwendung auf eine sehr spezifische Art und Weise aufgebaut wird.
Wenn Sie "C" umbrechen möchten, dann:
Wenn Sie "reines C" als Hauptklasse haben wollen, dann:
Fertig - so einfach ist das. Während Sie Ihre eigenen Rollen, wie Sie tun, ist sicherlich lehrreich (nein, wirklich - es ist und ich ermutige jeden, das zu erkunden), es erfindet einfach ein Rad neu.
tl; dr Wenn Sie gegen die System-APIs kämpfen, tun Sie es falsch.
Natürlich, aber ich portiere Rich's Foundation mit einem Löffel zu OS X. Es ist ein kompletter Zeitfresser, aber das entmutigt mich nicht in der mindestens
Super!
In diesem Fall sollten Sie sich die Implementierung von pythonw
und / oder (IIRC) ansehen, die Rubycocoa-Shell, die die Implementierung von GUI aus einem relativ nicht-Wrapper-basierten Shell-Skript ermöglicht .
Das Problem geht weit über die Hauptklasse hinaus. Beachten Sie, dass [NSBundle mainBundle]
wirklich sinnvoll sein muss und einige Ressourcen irgendwie eingekapselt werden müssen.
Außerdem hatte das PyObjC
-Projekt verschiedene Versuche, "Shell-Skript" -basierte Cocoa-Anwendungen auszuführen. Sie könnten über die verschiedenen Beispiele stochern, da ich denke, dass es immer noch mindestens ein paar gibt, die tun, was Sie wollen.
Eine Google-Suche nach "Cocoa-Anwendung von Shell-Skript" oder ähnlichem könnte ebenfalls nützlich sein, da dies in den letzten 23 Jahren mehrmals aufgetreten ist.
Wenn Sie bereit sind, die Objective-C-Laufzeitfunktionen aufzurufen, aber @implementation (aus irgendeinem verrückten Grund) nicht verwenden möchten, erstellen Sie einfach eine Klasse mit objc_allocateClassPair
und Freunden und verwenden Sie diese als Hauptklasse.
Tags und Links c objective-c macos cocoa objective-c-runtime