我正在尝试从Objective-C访问Swift类的Double?
属性。
class BusinessDetailViewController: UIViewController {
var lat : Double?
var lon : Double?
// Other elements...
}
在另一个视图控制器中,我正在尝试访问lat
,如下所示:
#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 */
}
我正在
在'BusinessDetailViewController *'
类型的对象上找不到属性'lat'
为什么我无法访问此属性?我错过了什么?
答案 0 :(得分:105)
非Objective-C类型的可选值未桥接到Objective-C。也就是说,下面的TestClass
的前三个属性将在Objective-C中可用,但第四个属性不会:
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
}
在Objective-C代码中,您将访问前三个属性,如下所示:
TestClass *optTest = [[TestClass alloc] init];
optTest.nsNumberOpt = @1.0;
optTest.nsNumberVar = @2.0;
optTest.doubleVar = 3.0;
在您的情况下,您可以将lat
和long
转换为非可选项,也可以将其切换为NSNumber
的实例。
请注意,如果采用第二种方法(将lat
和lon
切换为NSNumber
类型的非可选属性),则需要注意Objective-C代码 - 虽然Swift编译器会阻止您将nil
分配给非可选属性,但Objective-C编译器对于允许它没有任何疑虑,让nil
值潜入您的Swift代码而无法捕获它们在运行时。在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)
}
}
如果使用两个属性中的值调用,这可以正常工作,但如果{Objective} C代码中nsNumberVar
设置为nil
,则会在运行时崩溃。请注意,在使用之前,无法检查 nsNumberVar
是否为nil
!
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
答案 1 :(得分:12)
如果您的属性是Swift协议类型,只需在其前面添加@objc
即可。
示例:
class Foo: UIViewController {
var delegate: FooDelegate?
...
}
@objc protocol FooDelegate {
func bar()
}
答案 2 :(得分:3)
Optionals是一个快速的特定功能,在obj-c中不可用。可选的类实例可以工作,因为可以将nil可选映射到nil值,但值类型(int,float等)是不引用类型,因此这些类型的变量不会存储参考,但价值本身。
我不知道是否有解决方案 - 可能的解决方法是创建非可选属性,将nil
值映射到未使用的数据类型值(例如表示索引时的-1,或坐标为999999):
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
}
这应该将_lat
和_lon
属性公开给obj-c。
请注意,我从未尝试过,所以请告诉我们是否有效。
答案 3 :(得分:1)
[
UInt?
Int?
或Double?
属性]无法标记为@objc,因为其类型无法在Objective-C中表示。
然而,可以将它们“包装”在NSNumber中,如下所示:
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
}
}
}