Невозможно получить доступ к свойству Swift от Objective-C
Я пытаюсь вызвать var swift из объектного класса c. Что я делаю, как показано ниже:
Класс Swift
class BusinessDetailViewController: UIViewController {
var lat : Double?
var lon : Double?
@IBOutlet var mapView: MKMapView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// Here you can init your properties
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
В ViewController.m, я пытаюсь вызвать lat
следующим образом:
#import "i5km-Swift.h"
@interface ViewController ()
@property (strong, nonatomic) BusinessDetailViewController *businessDetailViewController;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.businessDetailViewController = [[BusinessDetailViewController alloc] initWithNibName:@"BusinessDetailViewController" bundle:nil];
self.businessDetailViewController.lat = businessArray[1]; /* THIS GIVES ME AN ERROR */
}
и я получаю
Property 'lat' not found on object of type 'BusinessDetailViewController *'
Любые идеи, по которым я не могу получить доступ, или мне не хватает чего-то другого.
Ответы
Ответ 1
Дополнительные значения типов не 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
Ответ 2
Если ваше свойство является типом протокола Swift, просто добавьте @objc
перед ним.
Пример:
class Foo: UIViewController {
var delegate: FooDelegate?
...
}
@objc protocol FooDelegate {
func bar()
}
Ответ 3
Опционы - это быстрая специфическая функция, недоступная в obj-c. Необязательные экземпляры классов работают, потому что необязательный параметр nil может быть сопоставлен с нулевым значением, но типы значений (int, float и т.д.) Являются not ссылочными типами, поэтому переменная этих типов не хранит ссылку, но само значение.
Я не знаю, есть ли решение - возможное обходное решение создает необязательные свойства, сопоставляющие значение 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.
Обратите внимание, что я никогда не пробовал это, поэтому, пожалуйста, сообщите нам, если он работает.