Невозможно получить доступ к классу 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
...
  1. Когда вы добавляете файл swift в свой проект Objective-C, Xcode предложит добавить файл заголовка моста Objective-C, поэтому разрешите создание файла заголовка.
  2. В вашем файле реализации 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.

Другие вопросы по тегам