xcode 公开给 Objective-C 代码时 Swift 类的名称不遵守 @objc 重命名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26132823/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 05:45:20  来源:igfitidea点击:

Name of Swift class when exposed to Objective-C code does not respect the @objc renaming

xcodeswift

提问by Manav

Given a declaration of a Swift class like

给定一个 Swift 类的声明,如

@objc(NSFoo) public class Foo {
   public func bar() -> () {}
}

I would expect, from my reading of the documentation, that on the Objective-C side of things we would be able to refer to this class using the identifier NSFoo. This is not what seems to be happening for me. The generated definition in ProjectName-Swift.his:

我希望,从我对文档的阅读来看,在 Objective-C 方面,我们将能够使用 identifier 来引用这个类NSFoo。对我来说,这似乎不是正在发生的事情。生成的定义ProjectName-Swift.h是:

SWIFT_CLASS("NSFoo")
@interface Foo
- (void)bar;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

whereas what I would expect is

而我期望的是

SWIFT_CLASS("Foo")
@interface NSFoo
...

I am using Xcode 6.0.1.

我正在使用 Xcode 6.0.1。

I missing something, or is this just a Xcode bug?

我遗漏了什么,或者这只是一个 Xcode 错误?

回答by milos

Note: Things have change since this answer was first written - see updates at the end!

注意:自从首次编写此答案以来,情况发生了变化 - 请参阅最后的更新!

Yeah, this does seam to be a bug... though, controlling Obj-C runtime names of methods does work:

是的,这确实是一个错误......不过,控制方法的 Obj-C 运行时名称确实有效:

Say we define a pair of minimal Obj-C and Swift classes that interact with each other:

假设我们定义了一对相互交互的最小 Obj-C 和 Swift 类:

Foo.swift

Foo.swift

import Foundation

@objc(SwiftFoo)
class Foo { // inheriting from NSObject makes no difference in this case

    @objc(postcardFromSwift)
    class func postcard() -> String {
        return "Postcard from Swift!"
    }

    @objc(getMailInSwift)
    class func getMail() {
        if let hello = NSBar.postcard() { // NSBar is an Obj-C class (see below)
            println("Printed in Swift: \(hello)")
        }
    }
}

NSBar.h

NSBar.h

#import <Foundation/Foundation.h>

@interface NSBar : NSObject
+ (NSString *)postcard;
+ (void)getMail;
@end

NSBar.m

NSBar.m

#import "NSBar.h"
#import "ObjS-Swift.h"

@implementation NSBar
+ (void)getMail {
    // notice that I am not referring to SwiftFoo in spite of @objc(SwiftFoo)
    printf("Printed in Objective C: %s", [[Foo postcardFromSwift] UTF8String]);
}
+ (NSString *)postcard {
    return @"Postcard from Objective C!";
}
@end

If we now call their class methods, say, from main.m:

如果我们现在调用它们的类方法,比如说,来自main.m

#import <Cocoa/Cocoa.h>
#import "NSBar.h"
#import "ObjS-Swift.h"

int main(int argc, const char * argv[]) {

    // notice that I am not referring to SwiftFoo in spite of @objc(SwiftFoo)
    [Foo getMailInSwift]; 
    [NSBar getMail];

    return NSApplicationMain(argc, argv);
}

This prints the following:

这将打印以下内容:

// --> Printed in Swift: Postcard from Objective C!
// --> Printed in Objective C: Postcard from Swift!

But it shouldn't have! Fooshould only be visible to Obj-C as SwiftFoosince that is what @objc(SwiftFoo)is promising to do. Indeed, using SwiftFootriggers the Use of undeclared identifiercompiler error instead. The fact that this did work for method names, leaves little doubt that this is a bug. I am just amazed that you seem to be the first to ask about it! Plus one for that!

但它不应该有!Foo应该只对 Obj-C 可见,SwiftFoo因为这@objc(SwiftFoo)是有前途的。实际上,使用SwiftFoo会触发Use of undeclared identifier编译器错误。事实上,这确实适用于方法名称,毫无疑问这是一个错误。我很惊讶你似乎是第一个提出这个问题的人!加一个!

And yes:

是的:

// <#ModuleName#>-Swift.h
SWIFT_CLASS("SwiftFoo")
@interface Foo
+ (NSString *)postcardFromSwift;
+ (void)getMailInSwift;

... does seam to be inverted for the class name, yet this is how that macro works – see WWDC video Swift Interoperability In Depth(c. 45 min and c. 48 min into the video). The relevant documentation is Exposing Swift Interfaces in Objective-C.

...确实要为类名反转接缝,但这就是该宏的工作方式 - 请参阅 WWDC 视频Swift 互操作性深入(视频中大约45 分钟和 48 分钟)。相关文档是在 Objective-C 中公开 Swift 接口

Xcode 7 beta 4

Xcode 7 测试版 4

The issue is now fixed (thanks to @ScottBerrevoets for the comment).

该问题现已修复(感谢@ScottBerrevoets 的评论)。

Xcode 7.1

Xcode 7.1

(thanks to @Pang for the comment)

(感谢@Pang 的评论)

@objc class C { } // error: only classes that inherit from NSObject can be declared @objc

回答by mkirk

Currently (in XCode8) this seems to have been addressed.

目前(在 XCode8 中)这似乎已得到解决。

Defined in XYZLogger.h and XYZLogger.m

在 XYZLogger.h 和 XYZLogger.m 中定义

NS_ASSUME_NONNULL_BEGIN

NS_SWIFT_NAME(Logger)
@interface XYZLogger : NSObject

+ (void)verbose:(NSString *)logString;
+ (void)debug:(NSString *)logString;
+ (void)info:(NSString *)logString;
+ (void)warn:(NSString *)logString;
+ (void)error:(NSString *)logString;

@end

NS_ASSUME_NONNULL_END

Used in objc like this:

像这样在 objc 中使用:

[XYZLogger debug:@"Hi from objective C"];

Used in Swift like this:

像这样在 Swift 中使用:

Logger.debug("Hi from swift");