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

前端 未结 2 1560
醉梦人生
醉梦人生 2021-02-07 04:39

Given a declaration of a Swift class like

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

I would expect, from my reading of

相关标签:
2条回答
  • 2021-02-07 05:19

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

    Defined in XYZLogger.h and 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:

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

    Used in Swift like this:

    Logger.debug("Hi from swift");
    
    0 讨论(0)
  • 2021-02-07 05:24

    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:

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

    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

    #import <Foundation/Foundation.h>
    
    @interface NSBar : NSObject
    + (NSString *)postcard;
    + (void)getMail;
    @end
    

    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:

    #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! Foo should only be visible to Obj-C as SwiftFoo since that is what @objc(SwiftFoo) is promising to do. Indeed, using SwiftFoo triggers the Use of undeclared identifier compiler 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!

    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.

    Xcode 7 beta 4

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

    Xcode 7.1

    (thanks to @Pang for the comment)

    @objc class C { } // error: only classes that inherit from NSObject can be declared @objc
    
    0 讨论(0)
提交回复
热议问题