Подтвердить что ты не робот

Название класса Swift при использовании кода Objective-C не учитывает переименование @objc

Учитывая объявление класса Swift, например

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

Я бы ожидал, что из моего чтения документации, что на стороне Objective-C мы могли бы обратиться к этому классу с помощью идентификатора NSFoo. Это не то, что, кажется, происходит для меня. Сгенерированное определение в ProjectName-Swift.h:

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

тогда как я ожидал бы

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

Я использую Xcode 6.0.1.

Я что-то пропустил, или это просто ошибка Xcode?

4b9b3361

Ответ 1

Примечание. Все изменилось, поскольку этот ответ был впервые написан - см. обновления в конце!

Да, это делает шов, чтобы быть ошибкой... хотя, контроль Obj-C runtime имена методов работает:

Скажем, мы определяем пару минимальных классов Obj-C и 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

#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

Если теперь мы будем называть их методы класса, например, из 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);
}

Отпечатано следующее:

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

Но этого не должно быть! Foo должен быть видимым только для Obj-C как SwiftFoo, поскольку это то, что обещает сделать @objc(SwiftFoo). В самом деле, используя SwiftFoo вместо этого запускает ошибку компилятора Use of undeclared identifier. Тот факт, что это работало для имен методов, оставляет мало сомнений в том, что это ошибка. Я просто удивлен, что вы, кажется, первым попросили об этом! Плюс один для этого!

И да:

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

... шов перевернут для имени класса, но вот как работает этот макрос - см. видео WWDC Swift Interoperability In Depth (около 45 минут и около 48 минут в видео). Соответствующая документация Предоставление Swift интерфейсов в Objective-C.

Xcode 7 beta 4

Теперь проблема исправлена ​​(спасибо @ScottBerrevoets для комментария).

Xcode 7.1

(спасибо @Pang за комментарий)

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

Ответ 2

В настоящее время (в XCode8) это, кажется, было рассмотрено.

Определено в 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

Используется в objc следующим образом:

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

Используется в Swift следующим образом:

Logger.debug("Hi from swift");