Невозможно получить доступ к классу 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!
}