无法从 Objective-C 访问 Swift 4 class:"Property not found on object of type"

Unable to access Swift 4 class from Objective-C: "Property not found on object of type"

使用最新的 Xcode 9 beta,我似乎完全无法访问 Swift classes 上的属性。更奇怪的是,我可以访问 class 本身来实例化它或其他任何东西,但完全无法访问它的属性。

所以如果我有这个 Swift class:

import UIKit

class TestViewController: UIViewController {
    var foobar = true
}

我尝试这样做:

TestViewController *testViewController = [[TestViewController alloc] init]; // success
testViewController.foobar; // error

我到底做错了什么? Xcode 9.

的新项目

将 Swift 代码公开给 Objective-C 的规则在 Swift 中已更改 4. 试试这个:

@objc var foobar = true

作为优化,@objc 推断在 Swift 4 中减少了。例如,属性 在 NSObject 派生的 class 中,例如你的 TestViewController,默认情况下 no 将不再推断 @objc(就像在 Swift 3 中所做的那样)。

或者,您也可以使用 @objcMembers:

立即将 所有 成员暴露给 Objective-C
@objcMembers class TestViewController: UIViewController {
    ...
}

此新设计在 the corresponding Swift Evolution proposal 中有完整的详细说明。

  1. 当您在 Objective-C 项目中添加 swift 文件时,Xcode 将提示添加 Objective-C 桥接 header 文件,因此允许创建 header 文件。
  2. 在您要访问 TestViewController 的 Objective-C 实现文件中 属性 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

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 *'[=14= 类型的 object 上找到]

因为 s1 没有前缀@objc。

你必须写:

@objc class MyClass: NSObject{

    @objc var s1: String?
    @objc var s2 : String?
}

(作为 side-note:在 C/C++/ObJC 文件中,始终将 system/general *h 文件放在 "local" class headers.)

Swift 4

只需在class之前添加@objcMembers @objcMembers class MyClassObject: NSObject { var s1:字符串! var s2: 字符串!

} Swift进化enter link description here

我在swift 3.0

中也遇到过这个问题

class 声明就是这样

class ClassA {
//statements
}

以上 class 无法在 Objective C 代码中访问,也未在 -Swift.h

中注册

一旦我像这样从 NSObject 继承:

class ClassA : NSObject {
//statements
} 

class 可在 Objective c 中访问并在 -Swift.h

中注册

当您不想避免从 NSobject 继承时,此解决方案很有用 class。

Xcode 10.2 | Swift 4 在 class 之前添加 @objcMembers 解决了我的问题。

@objcMembers class MyClass:NSObject {
   var s1: String!
   var s2: NSMutableArray!
}

至于Swift 5.1 发现"@objc"不够用,还要弄成public"@objc public":

@objc public class SomeClass: NSObject {
    @objc public let amount: NSNumber
...