2015-09-21 24 views
10

Lavorare su un framework misto. importato all'interno del file Obj-C ma le classi interne non sono visibili, solo quelle pubbliche.Come accedere a una classe Swift interna in Objective-C all'interno dello stesso framework?

La documentazione afferma chiaramente i clasees interni dovrebbero essere disponibili tra la Swift e Obj-C:

Importazione Swift in Objective-C
Per importare un insieme di file Swift nella stessa destinazione quadro come la vostra Codice Objective-C, non è necessario importare nulla nell'intestazione dell'ombrello per il framework. Invece, importa il file di intestazione generato da Xcode per il tuo codice Swift in qualsiasi file Objective-C .m da cui vuoi utilizzare il tuo codice Swift. Poiché l'intestazione generata per una destinazione quadro fa parte dell'interfaccia pubblica del framework , solo le dichiarazioni contrassegnate con il modificatore pubblico vengono visualizzate nell'intestazione generata per un obiettivo quadro. È possono ancora utilizzare i metodi e le proprietà che sono contrassegnati con il modificatore interna dall'interno della parte Objective-C del quadro Swift, finché sono dichiarate all'interno di una classe che eredita da una classe Objective-C . Per ulteriori informazioni sui modificatori del livello di accesso, vedere Access Control in The Swift Programming Language (Swift 2).

codice di esempio (Creare un nuovo progetto con un quadro)

// 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 

risposta

16

Come indicato nei documenti, dichiarazioni contrassegnati con internal modificatore non compaiono nella generata intestazione, quindi il compilatore non li conosce e quindi lamenta. Naturalmente, è possibile inviare messaggi utilizzando l'approccio performSelector, ma non è conveniente e soggetto a errori. Abbiamo solo bisogno di aiutare il compilatore a sapere che quelle dichiarazioni sono lì.

In primo luogo, abbiamo bisogno di usare @objc variante attributo che consente di specificare nome per il simbolo in Objective-C:

// SwiftObject.swift 

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

E poi non vi resta che creare @interface dichiarazione con i metodi che si desidera utilizzare nel codice - in modo che il compilatore sarà felice, e si applicano anche SWIFT_CLASS macro con il nome del simbolo che hai specificato in precedenza - in modo che il linker avrebbe scelto l'effettiva attuazione:

// SomeObject.m file 

SWIFT_CLASS("SWIFTYetAnotherSwiftObject") 
@interface YetAnotherSwiftObject : NSObject 

+ (void)doSomething; 

@end 


@implementation SomeObject 

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

@end 
  • Ho usato la dichiarazione dell'interfaccia nel file .m solo per chiarezza, l'opzione migliore sarebbe quella di combinare tali dichiarazioni nel file .h e includerlo.
  • Dichiarando i metodi in quell'interfaccia, stiamo facendo una promessa al compilatore, e non si lamenterà se ci metterai un metodo che non esiste (o con firma sbagliata, ecc.) Ovviamente, lo farai crash in runtime in quel caso, quindi sii cauto.
+0

Bello! Non sapevo di quella macro e Google non mostra molto. Hai qualche riferimento dai documenti Apple? – Yariv

+4

Bello? Questo è orribilmente prolisso e disordinato. E 'davvero questo quello che devi fare? Ho incontrato lo stesso problema e anche la mela avrebbe dovuto riuscire a fare qualcosa di meglio. Ho intenzione di rinunciare a questo e tornare all'obiettivo c, questo è irragionevole! +1 per pubblicare qualcosa che funzioni effettivamente (dopo ore di ricerca). –

+3

Secondo la documentazione di Apple "È ancora possibile utilizzare i metodi e le proprietà Swift contrassegnati con il modificatore interno dalla parte Objective-C del framework, a condizione che vengano dichiarati all'interno di una classe che eredita da una classe Objective-C", se la classe swift deriva da un'altra classe objc, dovrebbe essere disponibile nel codice objc. Ho un problema simile e ho contrassegnato la mia classe veloce con @objc e eredita da NSObject ma non è ancora disponibile nel codice objc. – puru020

3

Per me ha funzionato semplicemente controllando: "Consenti solo API estensione app".Lo trovi andando alle impostazioni del progetto, seleziona il tuo obiettivo e poi si trova nella scheda Generale sotto Informazioni di distribuzione.

Qualcuno può spiegarmi perché questo risolve il problema?

+0

Ti amo! LOL. Questo è l'unico posto sulla terra che ha trovato la risposta per aggirare questa stupida limitazione. Non dovrebbe essere richiesto alcun framework per esporre le sue classi Swift ai clienti delle API solo per essere in grado di utilizzare il codice ObjC interno! – nobre

+0

Fai attenzione a provare questa opzione! Elencherà la classe e i metodi nell'intestazione generata automaticamente. Usalo solo se non ti importa di mantenere quelli privati. – Amit

+0

Ma con questo controllo, mancano alcune API Cocoa. – Martin