2015-09-21 12 views
10

Arbeiten an einem gemischten Rahmen. importiert in die Obj-C-Datei, aber die internen Klassen sind nicht sichtbar, nur die öffentlichen.Wie kann man innerhalb desselben Frameworks auf eine interne Swift-Klasse in Objective-C zugreifen?

Die Dokumentation deutlich die interne clasees Staaten sollte zwischen Swift und Obj-C zur Verfügung: als

Importieren von Swift in Objective-C
So importieren Sie eine Reihe von Swift-Dateien im gleichen Rahmen Ziel Ihrer Objective-C-Code, Sie müssen nicht müssen alles in den Regenschirm-Header für das Framework importieren. Importieren Sie stattdessen die Xcode-generierte Header-Datei für Ihren Swift-Code in eine Objective-C .m-Datei, von der Sie Ihren Swift-Code verwenden möchten. Da der generierte Header für ein Framework-Ziel Teil der öffentlichen Schnittstelle des Framework ist, werden in der generierten Kopfzeile für ein Framework-Ziel nur Deklarationen angezeigt, die mit dem öffentlichen Modifikator markiert sind. Sie noch Swift Methoden und Eigenschaften verwenden, die mit dem internen Modifikator innerhalb des Objective-C Teils des Rahmens markiert sind, so lange werden sie innerhalb einer Klasse deklarieren, die von einer Objective-C-Klasse erbt . Weitere Informationen zu Zugriffsmodifikatoren finden Sie unter Access Control in The Swift Programming Language (Swift 2).

Codebeispiel (Erstellen Sie ein neues Projekt mit einem Rahmen)

// SwiftObject.swift 

public class SwiftObject: NSObject { 
    public class func doSomething() {} 
} 

internal class YetAnotherSwiftObject: NSObject { 
    internal class func doSomething() {} 
} 

// SomeObject.m file 

@implementation SomeObject 

- (void)someMethod { 
    [SwiftObject doSomething]; 
} 

- (void)someOtherMethod { 
    [YetAnotherSwiftObject doSomething]; // Use of undeclared identifier 
} 

@end 

Antwort

16

Wie in der Dokumentation angegeben, mit internal Modifikator markiert Erklärungen erscheinen nicht in der generierten Header, so dass der Compiler nicht über sie und damit über Beschwerden Bescheid weiß. Natürlich könnten Sie Nachrichten mit performSelector Ansatz senden, aber das ist nicht bequem und fehleranfällig. Wir müssen dem Compiler lediglich mitteilen, dass diese Deklarationen vorhanden sind.

Zuerst müssen wir @objc Attribut Variante verwenden, die Sie Namen für das Symbol in Objective-C angeben können:

// SwiftObject.swift 

@objc(SWIFTYetAnotherSwiftObject) 
internal class YetAnotherSwiftObject: NSObject { 
    internal class func doSomething() {} 
} 

Und dann brauchen Sie nur erstellen @interface Erklärung mit den Methoden, die Sie verwenden möchten in Ihrem Code - so wird der Compiler glücklich sein, und auch SWIFT_CLASS Makro mit dem Symbolnamen anwenden Sie zuvor angegeben haben - so der Linker würde die tatsächliche Implementierung wählen:

// SomeObject.m file 

SWIFT_CLASS("SWIFTYetAnotherSwiftObject") 
@interface YetAnotherSwiftObject : NSObject 

+ (void)doSomething; 

@end 


@implementation SomeObject 

- (void)someOtherMethod { 
    [YetAnotherSwiftObject doSomething]; // Should work now !!! 
} 

@end 
  • Ich habe die Interface-Deklaration in .m-Datei nur für die Klarheit verwendet, die bessere Option wäre, solche Deklarationen in .h-Datei zu kombinieren und es einzuschließen.
  • Indem wir Methoden in dieser Schnittstelle deklarieren, machen wir dem Compiler ein Versprechen, und es wird sich nicht beschweren, wenn Sie dort eine Methode einfügen, die nicht existiert (oder mit falscher Signatur usw.) in diesem Fall in der Laufzeit abstürzen - also Vorsicht.
+0

Schön! Ich wusste nicht über dieses Makro und Google zeigt nicht viel. Haben Sie eine Referenz aus den Apple-Dokumenten? – Yariv

+4

Schön? Das ist schrecklich ausführlich und chaotisch. Ist das wirklich was du tun musst? Ich bin auf dasselbe Problem gestoßen, und selbst Apple hätte etwas Besseres machen können. Ich gebe das auf und gehe zurück zum Ziel c, das ist unvernünftig! +1 für das Posten von etwas, das tatsächlich funktioniert (nach stundenlanger Suche). –

+3

Laut Apple-Dokumentation "Sie können Swift-Methoden und -Eigenschaften, die mit dem internen Modifikator markiert sind, weiterhin innerhalb des Objective-C-Teils Ihres Frameworks verwenden, solange sie in einer Klasse deklariert sind, die von einer Objective-C-Klasse erbt." Wenn die Swift-Klasse von einer anderen Objc-Klasse abgeleitet wird, sollte sie in Objc-Code verfügbar sein. Ich habe ein ähnliches Problem und ich habe meine Swift-Klasse mit @objc markiert und es erbt von NSObject, aber immer noch nicht in Objc-Code. – puru020

3

Für mich funktionierte es nur durch Überprüfung: "Erlaube App Erweiterung API nur".Sie finden es, indem Sie zur Projekteinstellung gehen, Ihr Ziel auswählen und es befindet sich dann auf der Registerkarte Allgemein unter Deployment-Info.

Kann mir jemand erklären, warum das das Problem löst?

+0

Ich liebe dich! LOL. Das ist der einzige Ort auf der Welt, der die Antwort gefunden hat, diese dumme Begrenzung zu umgehen. Es sollte kein Framework erforderlich sein, um Swift-Klassen API-Konsumenten zugänglich zu machen, nur um mit internem ObjC-Code interagieren zu können! – nobre

+0

Seien Sie vorsichtig, wenn Sie diese Option ausprobieren! Es wird die Klasse und Methoden in automatisch generierten Header auflisten. Benutze es nur, wenn es dir nicht wichtig ist, diese privat zu halten. – Amit

+0

Aber mit diesem Häkchen wird eine Menge Cocoa API fehlen. – Martin

Verwandte Themen