2014-10-14 13 views
50

Ich versuche, auf die Eigenschaft Double? einer Swift-Klasse von Objective-C zuzugreifen.Zugriff auf Eigenschaft vom Typ "Swift" aus Objective-C nicht möglich

class BusinessDetailViewController: UIViewController { 

    var lat : Double? 
    var lon : Double? 

    // Other elements... 
} 

In einem anderen View-Controller, versuche ich lat wie folgt zugreifen:

#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 */ 
} 

und ich bin

Property 'lat' nicht auf dem Objekt gefunden Typs bekommen ‚BusinessDetailViewController * '

Warum kann ich nicht a Zugriff auf diese Eigenschaft? Was vermisse ich?

+0

Ich weiß nicht, weil in businessDetailViewController, ich habe auch einen Auslass '@IBOutlet var mapView: MKMapView ? 'und ich kann von außen darauf zugreifen, aber es hat keine' public' – tranvutuan

+0

Ich denke, optionale Strukturen sind in Objective-C nicht sichtbar. Wird validiert. –

Antwort

95

Optionale Werte von Nicht-Objective-C-Typen werden nicht in Objective-C überbrückt. Das heißt, die ersten drei Eigenschaften von TestClass unter würden in Objective-C zur Verfügung, aber die vierten würde nicht:

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 
} 

In Ihrem Objective-C-Code, dann würden Sie diese ersten drei Eigenschaften zugreifen wie dies:

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

In Ihrem Fall können Sie entweder konvertieren lat und long als nicht Optional oder schalten sie Instanzen von NSNumber zu sein.


Beachten Sie, dass Sie über Ihre Objective-C-Code vorsichtig sein, wenn Sie den zweiten Ansatz (lat und lon zu nicht-optionalen Eigenschaften des Typs Schalt NSNumber) - während der Swift-Compiler Sie verhindern wird aus Wenn der Objective-C-Compiler nil nicht-optionalen Eigenschaften zuweist, hat er keine Bedenken, ihn zuzulassen. Werte nil schleichen sich in Ihren Swift-Code ein, ohne dass sie zur Laufzeit abgefangen werden können. Betrachten Sie diese Methode auf 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) 
    } 
} 

Dies funktioniert gut, wenn mit den Werten in beide der Eigenschaften aufgerufen, aber wenn nsNumberVar-nil von dem Objective-C-Code festgelegt ist, wird diese zur Laufzeit zum Absturz bringen. Beachten Sie, dass keine Möglichkeit gibt, zu überprüfen, ob nsNumberVarnil ist, bevor Sie es verwenden!

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 
+0

Ich konnte es in den Dokumenten nicht aufspüren, aber der Compiler wird Ihnen sagen, dass es nicht mit '@objc Protokoll FooProtocol {var lat: Double? {get}} ' –

+1

Die Dokumentation dazu ist lückenhaft - z. B. [diese Seite] (https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html) sagt diese Aufzählungen und Strukturen, die in Swift definiert sind, sind in Obj-C nicht verfügbar, erwähnen aber nicht, dass Optionals (die als'Enum' implementiert sind) und die meisten der gebauten 'struct' Typen richtig überbrücken, bis Sie auf [die Seite auf Cocoa-Datentypen] (https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-XID_41). –

+0

@NateCook Ich kann es nicht beweisen, aber ich denke, eine optionale "NSNumber" ist überbrückt und eine optionale "Int" oder "Float" ist nicht, weil 'NSNumber' ist ein Referenztyp, und' .None' ist zugeordnet ' nil ', während ein Werttyp in objc kein' nil'-Gegenstück hat. Ich korrigiere dich nicht, frage mich nur, ob du mir zustimmst – Antonio

3

Optionals ist eine schnelle spezifische Funktion, die in obj-c nicht verfügbar ist. Optionale Klasseninstanzen funktionieren, weil nil optional einem Wert von nil zugeordnet werden kann, aber Werttypen (int, floats usw.) sind nicht Referenztypen, daher speichert Variable dieser Typen keine Referenz, sondern den Wert selbst .

Ich weiß nicht, ob es eine Lösung gibt - eine mögliche Abhilfe schafft nicht optionale Eigenschaften Abbildung des nil Wert auf einen nicht verwendeten Datentyp Wert (zB -1, wenn Sie einen Index darstellt, oder 999999 für eine Koordinate):

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 
} 

Das sollte die _lat und _lon Eigenschaften zu obj-c.

Beachten Sie, dass ich das nie ausprobiert habe, also lass es uns wissen, wenn es funktioniert.

+0

versuchen Sie es einfach und ja, wir können von außen auf _lat und _lon zugreifen. Vielen Dank. – tranvutuan

+0

Cool - danke für das Teilen. – Antonio

8

Wenn Ihre Eigenschaft ein Swift-Protokolltyp ist, fügen Sie einfach @objc davor hinzu.

Beispiel:

class Foo: UIViewController { 
    var delegate: FooDelegate? 
    ... 
} 

@objc protocol FooDelegate { 
    func bar() 
} 
0

[UInt?Int? oder Double? Eigenschaften] nicht markiert @objc werden, weil seine Art nicht in Objective-C dargestellt werden.

Es ist jedoch möglich, zu "wickeln", um sie in einem NSNumber etwa so:

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