Невозможно получить доступ к классу 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.
Ответы
Ответ 1
Правила предоставления кода Swift Objective-C изменились в Swift 4. Попробуйте вместо этого:
@objc var foobar = true
В качестве оптимизации вывод @objc
был уменьшен в Swift 4. Например, свойство в классе NSObject
-derived, такое как ваш TestViewController
, больше не будет выводить @objc
по умолчанию ( как это было в Swift 3).
В качестве альтернативы, вы также можете открыть все члены Objective-C одновременно, используя @objcMembers
:
@objcMembers class TestViewController: UIViewController {
...
}
Этот новый дизайн подробно описан в соответствующем предложении Swift Evolution.
Ответ 2
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 для каждого свойства.
Итак:
Swift 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 4
просто добавьте @objcMembers перед классом
@objcMembers class MyClassObject: NSObject
{ var s1: Строка! var s2: String!
}
Swift evolutionвведите описание ссылки здесь
Ответ 3
- Когда вы добавляете быстрый файл в проект 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
Ответ 4
Я также столкнулся с этой проблемой в Swift 3.0
объявление класса было так
class ClassA {
//statements
}
вышеупомянутый класс не был доступен в коде Objective C, и он также не был зарегистрирован в -Swift.h
как только я унаследовал от NSObject, как это:
class ClassA : NSObject {
//statements
}
класс был доступен в Objective c и был зарегистрирован в -Swift.h
Это решение полезно, когда вы не хотите избегать наследования от класса NSobject.
Ответ 5
Xcode 10.2 | Swift 4
Добавление @objcMembers
перед классом решило мою проблему.
@objcMembers class MyClass:NSObject {
var s1: String!
var s2: NSMutableArray!
}