无法从Objective-C访问Swift 4类:“在类型对象上未找到的属性”

时间:2023-01-15 14:58:55

Using the latest Xcode 9 beta, I'm seemingly completely unable to access properties on Swift classes. Even odder, I can access the class itself to instantiate it or whatever, but completely unable to access properties on it.

使用最新的Xcode 9 beta,我似乎完全无法访问Swift类上的属性。即使是odder,我也可以访问类本身来实例化它,但是完全不能访问它上的属性。

So if I have this Swift class:

如果我有这个Swift类:

import UIKit

class TestViewController: UIViewController {
    var foobar = true
}

And I try to do this:

我试着这么做:

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

What exactly am I doing wrong? New project with Xcode 9.

我到底做错了什么?使用Xcode 9的新项目。

3 个解决方案

#1


43  

The rules for exposing Swift code to Objective-C have changed in Swift 4. Try this instead:

将Swift代码公开给Objective-C的规则在Swift 4中发生了变化。试试这个:

@objc var foobar = true

As an optimization, @objc inference have been reduced in Swift 4. For instance, a property within an NSObject-derived class, such as your TestViewController, will no longer infer @objc by default (as it did in Swift 3).

作为一个优化,@objc推理在Swift 4中被减少。例如,nsobject派生类中的属性(比如TestViewController)在默认情况下不再推断@objc(就像在Swift 3中那样)。

Alternatively, you could also expose all members to Objective-C as well using @objcMembers:

或者,也可以使用@objcMembers将所有成员公开给Objective-C:

@objcMembers class TestViewController: UIViewController {
    ...
}

The new design is fully detailed in the corresponding Swift Evolution proposal.

新设计在相应的快速进化方案中得到了充分的详细说明。

#2


5  

Swift 3.2/4.0 / XCode 9.1

Swift 3.2/4.0 / XCode 9.1

You you set swift3.2 in project settings ( //:configuration = Debug SWIFT_VERSION = 3.2 )

在项目设置中设置swift3.2(/:配置= Debug SWIFT_VERSION = 3.2)

you can use your code,(using the correct import file in objc, see below). If You set project to swift 4.0 ( //:configuration = Debug SWIFT_VERSION = 4.0 )

您可以使用您的代码(使用objc中正确的导入文件,请参见下面)。如果将项目设置为swift 4.0 (/:configuration = Debug SWIFT_VERSION = 4.0)

You must prepend @objc for every property.

对于每个属性,都必须预先使用@objc。

So:

所以:

Swift 3.2:

斯威夫特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;
}

works.

的工作原理。

Swift 4.0:

斯威夫特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;
}

does NOT works: compiler fails:

不工作:编译失败:

/Users....ViewController.m:24:21: Property 's1' not found on object of type 'MyClass *'

/用户.... ViewController。m:24:21:在“MyClass *”类型的对象上没有找到属性“s1”

as s1 is not prepended with @objc.

因为s1不是用@objc预写的。

You must write:

你必须写:

@objc class MyClass: NSObject{

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

(As a side-note: in C/C++/ObJC file, put always system/general *h files before your "local" class headers.)

(附带说明:在C/ c++ /ObJC文件中,始终在“本地”类头之前放置系统/通用*h文件。)

#3


0  

  1. When you add a swift file in your Objective-C project, Xcode will prompt to add Objective-C bridging header file, so allow the header file to be created.
  2. 当您在Objective-C项目中添加一个swift文件时,Xcode将提示添加Objective-C桥接头文件,因此允许创建头文件。
  3. In your Objective-C implementation file where you want to access the TestViewController property foobar. Use the following import syntax and replace the ProjectName with your project.
  4. 在Objective-C实现文件中访问TestViewController属性foobar。使用以下导入语法,并将项目名替换为项目名。

#import "ProjectName-Swift.h"

#进口“ProjectName-Swift.h”

Objective-C implementation file:

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

For more details go through the Apple Documents

有关更多细节,请参阅苹果公司的文件

#1


43  

The rules for exposing Swift code to Objective-C have changed in Swift 4. Try this instead:

将Swift代码公开给Objective-C的规则在Swift 4中发生了变化。试试这个:

@objc var foobar = true

As an optimization, @objc inference have been reduced in Swift 4. For instance, a property within an NSObject-derived class, such as your TestViewController, will no longer infer @objc by default (as it did in Swift 3).

作为一个优化,@objc推理在Swift 4中被减少。例如,nsobject派生类中的属性(比如TestViewController)在默认情况下不再推断@objc(就像在Swift 3中那样)。

Alternatively, you could also expose all members to Objective-C as well using @objcMembers:

或者,也可以使用@objcMembers将所有成员公开给Objective-C:

@objcMembers class TestViewController: UIViewController {
    ...
}

The new design is fully detailed in the corresponding Swift Evolution proposal.

新设计在相应的快速进化方案中得到了充分的详细说明。

#2


5  

Swift 3.2/4.0 / XCode 9.1

Swift 3.2/4.0 / XCode 9.1

You you set swift3.2 in project settings ( //:configuration = Debug SWIFT_VERSION = 3.2 )

在项目设置中设置swift3.2(/:配置= Debug SWIFT_VERSION = 3.2)

you can use your code,(using the correct import file in objc, see below). If You set project to swift 4.0 ( //:configuration = Debug SWIFT_VERSION = 4.0 )

您可以使用您的代码(使用objc中正确的导入文件,请参见下面)。如果将项目设置为swift 4.0 (/:configuration = Debug SWIFT_VERSION = 4.0)

You must prepend @objc for every property.

对于每个属性,都必须预先使用@objc。

So:

所以:

Swift 3.2:

斯威夫特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;
}

works.

的工作原理。

Swift 4.0:

斯威夫特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;
}

does NOT works: compiler fails:

不工作:编译失败:

/Users....ViewController.m:24:21: Property 's1' not found on object of type 'MyClass *'

/用户.... ViewController。m:24:21:在“MyClass *”类型的对象上没有找到属性“s1”

as s1 is not prepended with @objc.

因为s1不是用@objc预写的。

You must write:

你必须写:

@objc class MyClass: NSObject{

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

(As a side-note: in C/C++/ObJC file, put always system/general *h files before your "local" class headers.)

(附带说明:在C/ c++ /ObJC文件中,始终在“本地”类头之前放置系统/通用*h文件。)

#3


0  

  1. When you add a swift file in your Objective-C project, Xcode will prompt to add Objective-C bridging header file, so allow the header file to be created.
  2. 当您在Objective-C项目中添加一个swift文件时,Xcode将提示添加Objective-C桥接头文件,因此允许创建头文件。
  3. In your Objective-C implementation file where you want to access the TestViewController property foobar. Use the following import syntax and replace the ProjectName with your project.
  4. 在Objective-C实现文件中访问TestViewController属性foobar。使用以下导入语法,并将项目名替换为项目名。

#import "ProjectName-Swift.h"

#进口“ProjectName-Swift.h”

Objective-C implementation file:

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

For more details go through the Apple Documents

有关更多细节,请参阅苹果公司的文件