Не удается получить доступ к свойству типа Swift из Objective-C
Я пытаюсь получить доступ к классу Swift Double?
свойство из Objective-C.
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 */
}
и я получаю
Свойство 'lat' не найдено для объекта типа 'BusinessDetailViewController *'
Почему я не могу получить доступ к этой собственности? Что мне не хватает?
4 ответа
Необязательные значения типов не-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
,
Обратите внимание, что вы должны быть осторожны с вашим кодом Objective C, если вы выбираете второй подход (переключение lat
а также lon
на необязательные свойства типа NSNumber
) - тогда как компилятор 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)
}
}
Это прекрасно работает, если вызывается со значениями в обоих свойствах, но если nsNumberVar
установлен в nil
из кода Objective-C, это будет сбой во время выполнения. Обратите внимание, что нет способа проверить, действительно ли 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
Если ваше свойство является типом протокола Swift, просто добавьте @objc
перед ней.
Пример:
class Foo: UIViewController {
var delegate: FooDelegate?
...
}
@objc protocol FooDelegate {
func bar()
}
[
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
}
}
}
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.
Обратите внимание, что я никогда не пробовал, поэтому, пожалуйста, дайте нам знать, если это работает.