Невозможно получить доступ к классу Swift 4 из Objective-C: "Свойство не найдено для объекта типа"
Используя последнюю бета-версию Xcode 9, я, по-видимому, совершенно не могу получить доступ к свойствам классов Swift. Даже странно, я могу получить доступ к самому классу, чтобы создать его экземпляр или что-то еще, но совершенно не могу получить доступ к свойствам этого класса.
Так что, если у меня есть этот класс Swift:
import UIKit
class TestViewController: UIViewController {
var foobar = true
}
И я пытаюсь сделать это:
TestViewController *testViewController = [[TestViewController alloc] init]; // success
testViewController.foobar; // error
Что именно я делаю не так? Новый проект с Xcode 9.
4 ответа
Правила предоставления кода Swift Objective-C изменились в Swift 4. Попробуйте вместо этого:
@objc var foobar = true
В качестве оптимизации, @objc
вывод был уменьшен в Swift 4. Например, свойство в NSObject
класс, такой как ваш TestViewController
больше не будет выводить @objc
по умолчанию (как это было в Swift 3).
В качестве альтернативы, вы также можете открыть все члены Objective-C одновременно, используя @objcMembers
:
@objcMembers class TestViewController: UIViewController {
...
}
Новый дизайн полностью детализирован в соответствующем предложении Swift Evolution.
Swift 3.2/4.0 / XCode 9.1
Вы устанавливаете swift3.2 в настройках проекта (//: configuration = Debug SWIFT_VERSION = 3.2)
Вы можете использовать свой код (используя правильный файл импорта в objc, см. ниже). Если вы установите проект на swift 4.0 (//: configuration = Debug SWIFT_VERSION = 4.0)
Вы должны добавить @objc для каждого свойства.
Так:
Свифт 3.2:
// MyClass.swift
@objc class MyClass: NSObject{
var s1: String?
@objc var s2 : String?
}
//
// ViewController.m
import "MixingObjCAndSwift-Swift.h"
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MyClass * mc = [MyClass new];
NSString * s1 = mc.s1;
NSString * s2 = mc.s2;
}
работает.
Swift 4.0:
// MyClass.swift
@objc class MyClass: NSObject{
var s1: String?
@objc var s2 : String?
}
.....
- (void)viewDidLoad {
[super viewDidLoad];
MyClass * mc = [MyClass new];
NSString * s1 = mc.s1;
NSString * s2 = mc.s2;
}
НЕ работает: компилятор не работает:
/Users....ViewController.m:24:21: Свойство 's1' не найдено для объекта типа 'MyClass *'
поскольку s1 не предшествует @objc.
Вы должны написать:
@objc class MyClass: NSObject{
@objc var s1: String?
@objc var s2 : String?
}
(Как примечание: в файле C/C++/ObJC всегда ставьте системные / общие *h файлы перед вашими "локальными" заголовками классов.)
Что касается Swift 5.1, я обнаружил, что "@objc" недостаточно, но также сделайте его общедоступным "@objc public":
@objc public class SomeClass: NSObject {
@objc public let amount: NSNumber
...
- Когда вы добавляете файл swift в свой проект Objective-C, Xcode предложит добавить файл заголовка моста Objective-C, поэтому разрешите создание файла заголовка.
- В вашем файле реализации Objective C, где вы хотите получить доступ к свойству TestViewController foobar. Используйте следующий синтаксис импорта и замените ProjectName своим проектом.
#import "ProjectName-Swift.h"
Файл реализации Objective-C:
#import "ViewController.h"
#import "ProjectName-Swift.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
TestViewController *testViewController = [[TestViewController alloc] init]; // success
BOOL prop = testViewController.foobar;
NSLog(@"Property: %d", prop);
}
@end
Для более подробной информации обратитесь к Apple Documents
Xcode 10.2 | Swift 4 Добавление @objcMembers
до того, как класс решил мою проблему.
@objcMembers class MyClass:NSObject {
var s1: String!
var s2: NSMutableArray!
}
Я также столкнулся с этой проблемой в Swift 3.0
объявление класса было так
class ClassA {
//statements
}
вышеупомянутый класс не был доступен в коде Objective C, и он также не был зарегистрирован в -Swift.h
как только я унаследовал от NSObject, как это:
class ClassA : NSObject {
//statements
}
класс был доступен в Objective c и был зарегистрирован в -Swift.h
Это решение полезно, когда вы не хотите избегать наследования от класса NSobject.