Imansible accedere alla proprietà sul tipo Swift da Objective-C

Sto tentando di accedere a Double? Swift class Double? proprietà da Objective-C.

 class BusinessDetailViewController: UIViewController { var lat : Double? var lon : Double? // Other elements... } 

In un’altra vista controller, sto cercando di accedere a lat come segue:

 #import "i5km-Swift.h" @interface ViewController () @property (strong, nonatomic) BusinessDetailViewController *businessDetailViewController; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.businessDetailViewController = [[BusinessDetailViewController alloc] initWithNibName:@"BusinessDetailViewController" bundle:nil]; self.businessDetailViewController.lat = businessArray[1]; /* THIS GIVES ME AN ERROR */ } 

e sto diventando

Proprietà ‘lat’ non trovata su object di tipo ‘BusinessDetailViewController *’

Perché non posso accedere a questa proprietà? Cosa mi manca?

I valori opzionali dei tipi non-Objective-C non sono colmati in Objective-C. Cioè, le prime tre proprietà di TestClass seguito sarebbero disponibili in Objective-C, ma la quarta non sarebbe:

 class TestClass: NSObject { var nsNumberVar: NSNumber = 0 // obj-c type, ok var nsNumberOpt: NSNumber? // optional obj-c type, ok var doubleVar: Double = 0 // bridged Swift-native type, ok var doubleOpt: Double? // not bridged, inaccessible } 

Nel tuo codice Objective-C, devi accedere a queste prime tre proprietà come questa:

 TestClass *optTest = [[TestClass alloc] init]; optTest.nsNumberOpt = @1.0; optTest.nsNumberVar = @2.0; optTest.doubleVar = 3.0; 

Nel tuo caso, puoi convertire lat e long per essere non-Opzionali o convertirli in istanze di NSNumber .


Nota che devi fare attenzione al tuo codice Objective-C se NSNumber il secondo approccio (passando da lat e lon a proprietà non facoltative di tipo NSNumber ) – mentre il compilatore Swift ti impedirà di assegnare nil a proprietà non facoltative , il compilatore Objective-C non ha remore a permetterlo, lasciando che i valori nil introducano nel tuo codice Swift senza possibilità di catturarli in fase di runtime. Considera questo metodo su TestClass :

 extension TestClass { func badIdea() { // print the string value if it exists, or 'nil' otherwise println(nsNumberOpt?.stringValue ?? "nil") // non-optional: must have a value, right? println(nsNumberVar.stringValue) } } 

Funziona bene se invocato con valori in entrambe le proprietà, ma se nsNumberVar è impostato su nil dal codice Objective-C, questo si bloccherà in fase di esecuzione. Nota che non c’è modo di verificare se nsNumberVar è nil prima di usarlo!

 TestClass *optTest = [[TestClass alloc] init]; optTest.nsNumberOpt = @1.0; optTest.nsNumberVar = @2.0; [optTest badIdea]; // prints 1, 2 optTest.nsNumberOpt = nil; optTest.nsNumberVar = nil; [optTest badIdea]; // prints nil, then crashes with an EXC_BAD_ACCESS exception 

Se la tua proprietà è un tipo di protocollo Swift, aggiungi @objc di fronte ad esso.

Esempio:

 class Foo: UIViewController { var delegate: FooDelegate? ... } @objc protocol FooDelegate { func bar() } 

Optionals è una funzionalità specifica rapida, non disponibile in obj-c. Le istanze di classi facoltative funzionano perché un valore nil opzionale può essere mappato su un valore nullo, ma i tipi di valore (int, float, ecc.) Non sono tipi di riferimento, quindi una variabile di questi tipi non memorizza un riferimento, ma il valore stesso.

Non so se esiste una soluzione: una ansible soluzione alternativa è la creazione di proprietà non facoltative che associano il valore nil a un valore di tipo di dati inutilizzato (ad esempio -1 quando si rappresenta un indice o 999999 per una coordinata):

 class Test { var lat : Double? { didSet { self._lat = self.lat != nil ? self.lat! : 999999 } } var lon : Double? { didSet { self._lon = self.lon != nil ? self.lon! : 999999 } } var _lat: Double = 99999999 var _lon: Double = 99999999 } 

Questo dovrebbe esporre le proprietà _lat e _lon a obj-c.

Si noti che non l’ho mai provato, quindi fatecelo sapere se funziona.

[ UInt? Int? o Double? proprietà] non può essere marcato @objc perché il suo tipo non può essere rappresentato in Objective-C.

È, tuttavia, ansible “avvolgerli” in un NSNumber in questo modo:

 class Foo { var bar:Double? } // MARK: Objective-C Support extension Foo { /// bar is `Double?` in Swift and `(NSNumber * _Nullable)` in Objective-C @objc(bar) var z_objc_bar:NSNumber? { get { return bar as NSNumber? } set(value) { bar = value?.doubleValue ?? nil } } }