Objective-C代码能调用Swift类扩展吗?

121

我搜索了一些帖子,我认为我不能在Swift下编写一个扩展(extension),并从Objective-C代码中调用它,对吗?

@objc等类似属性只支持方法、类和协议吗?


1
为什么不试一试呢? - HAS
7
软件报错了,但我需要一个明确的答案。 - sprhawk
6个回答

119

您可以编写一个Swift扩展并在Objective-C代码中使用它。已经使用Xcode 6.1.1进行了测试。

您只需要:

  • 在Swift中创建您的扩展(自Swift 4.0.3以来需要@objc注释)

  • 在Objective-C类中导入#import "ProjectTarget-Swift.h"(其中“ProjectTarget”表示与Swift扩展相关联的XCode目标)

  • 调用Swift扩展中的方法


8
我已经按照这样做了,但还是编译时出错了。 嗯。编辑:我导入了我的桥接头文件,而不是“ProjectTarget-Swift.h”。 呆。 - Jason Renaldo
两者都是桥接头文件。区别在于一个用于在ObjC中使用Swift代码,另一个用于在Swift中使用ObjC代码。Swift头文件是不可见的。另一个应该由您管理。 - marius bardan
William Hu,请查看mclaughlinj的答案! - appleitung
40
从Swift 4.0.3开始,如果你想在Objective C类文件中使用扩展(extension),则需要使用@objc注释。 - Rizwan Ahmed
注意:如果您的项目目标名称中有破折号,则需要从导入语句中删除该破折号。例如,如果您的项目目标名称为“project-target”,则导入语句应为“projecttarget-Swift.h”。 - Tyler Wood

84

我发现在 Swift 4.0 中,我必须在我的 extension 关键字前面添加 @objc,才能让我扩展的 Objc 类型实例看到 Swift 扩展方法。

简而言之:

文件配置设置:

CustomClass.h
CustomClass.m
CustomClassExtension.swift

在CustomClassExtension中:

@objc extension CustomClass
{
    func method1() 
    {
        ...
    }
}

在我的AppDelegate.m文件中:

self.customClass = [[CustomClass alloc] init];
[self.customClass method1];

3
如果一个方法使用泛型,它就不能被Objective-C使用,你需要添加@nonobjc注释。 - ThomasW
只是一点小提示,@objcMembers 在这种情况下不起作用。不知道为什么.. :-( - Raunak

51

这个解决方案适用于 Swift 2.2 和 Swift 3。请注意,仅限于类的扩展(而不是结构体或枚举)将可从 Objective-C 中访问。

这个解决方案适用于Swift 2.2和Swift 3。请注意,只有类的扩展(而不是结构体或枚举的扩展)可以从Objective-C中访问。
import UIKit

extension UIColor {

    //Custom colours
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}

在您的 ObjC 文件中,然后导入 #import "ProductModuleName-Swift.h"

Swift 4

extension UIColor {

    // As of Swift 4.0.3, the @objc annotation is needed if you want to use the extension in Objective-C files
    @objc
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}

1
@DanRosenstark 您是正确的。我正在将其更改为“ProductModuleName-Swift.h”,正如苹果建议的那样:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-ID126 - Foti Dim
1
在 Swift 3 中运行良好。 - Viktor Kucera
我需要使用桥接头吗? - jegadeesh
不,你使用桥接头文件将 ObjC 代码导入到 Swift 中。这里是相反的情况。 - Foti Dim
@LeeKang,我刚刚尝试了 #import "ProductModuleName-Swift.h",没有将扩展公开,它也对我起作用了。 - David Marcus
显示剩余2条评论

44

如其他答案所述,在大多数情况下,导入生成的Swift头文件是有效的。

但有一个例外,即当类别定义在桥接类型上时(即扩展定义在String而不是NSString上)。这些类别将无法自动桥接到它们的Objective-C对应项。为了解决这个问题,您需要使用Objective-C类型(并在您的Swift代码中使用as String进行返回值转换),或者定义Swift和Objective-C类型的扩展。


2
补充上面的答案,你应该将你的 Swift 扩展设置为公共的,并将其类型设置为 NSString,例如 public extension NSString。如果在编译时出现未解决的标识符或类似的错误,你可以再次将其转换回 String,例如 let sVal = self as String,然后在 sVal 上调用必要的代码。 - RunLoop
@RunLoop 实际上你不需要 public,没有访问控制符也可以工作。而且(我是指导出到 Obj-C)对于字符串来说是不起作用的,因为它们是结构体,而不是类,并且只能从 Swift 中使用。所以,是的 - 你可以编写 NSString 的扩展并使用转换,或者像 mclaughlinj 所说的那样,编写 NSString 类和 String 结构体的扩展。 - Alex Nazarov

3

在Objective-C文件中导入"#import "ProductModuleName-Swift.h"头文件,并在Swift文件中的extension前面添加@objc。这样可以在Swift 4.2和Swift 5中正常工作。


2
如果您认为已经正确配置了所有内容(使用@objcMembers或@objc标记了Swift实体,导入了桥接头文件“ProductModuleName-Swift.h”等),但仍然出现“No visible @interface for 'FooClass' declares the selector 'fooSelector'”错误:
请通过ctrl + cmd单击查看桥接头文件中是否显示了您的接口。如果没有,请查看我对此问题的回答:Swift to Objective-C header does not contain Swift classes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接