转换为 Swift 3 重命名了我自己的 Objective-C 方法

Posted

技术标签:

【中文标题】转换为 Swift 3 重命名了我自己的 Objective-C 方法【英文标题】:Converting to Swift 3 renamed my own Objective-C method 【发布时间】:2016-10-20 14:21:55 【问题描述】:

我在我的 Objective-C 代码中混合了 swift 类。使用 Swift 2.3,一切都很好并且按预期工作。

我最近转换到 Swift 3,它更新了几个 API 调用,因为 Swift 3 发生了所有重命名。我明白了。

但不好的是,Swift 3 似乎已经重命名了 my Objective-C 类之一中的方法。我拥有 Objective-C 类,我调用了我想要的方法:readDeliveryInfoItems。但是现在,在转换为 Swift 3 之后,我不能在我的 Swift 类中再调用 .readDeliveryInfoItems() 了。它告诉我它已重命名为.readItems()

这没有任何意义。而且Objective-C类仍然调用方法readDeliveryInfoItems,所以这里有一些秘密。

我尝试将 Objective-C 的 readDeliveryInfoItems 方法重命名为 readDeliveryInfo,构建(Swift 失败,因为它说 readInfo() 方法不存在,这很好),然后将方法重命名为readDeliveryInfoItems。但是,当我在此之后构建时,Swift 又回到认为该方法称为 readInfo()。我希望这会诱使 Xcode 刷新 Swift 桥接并将方法重命名为正确的名称 readDeliveryInfoItems(),但它没有。

我该如何解决这个问题?

更新以添加更多信息

我的 Objective-C 类的接口有这个函数声明:

- (nullable NSArray<XMPPDeliveryInfoItem *> *)readDeliveryInfoItems;

但是在该类的 Generated Interface(见下面 MartinR 的评论)中,函数声明是这样的:

open func readItems() -> [XMPPDeliveryInfoItem]?

该类中还有其他类似readDeliveryInfoItems函数的函数,比如这个:

- (nullable NSArray<XMPPDeliveryInfoItem *> *)sentDeliveryInfoItems;

它们在生成的界面中看起来是正确的:

open func sentDeliveryInfoItems() -> [XMPPDeliveryInfoItem]?

所以我无法弄清楚为什么我只有一个功能会遇到这个问题。

【问题讨论】:

您可以使用NS_SWIFT_NAME 来控制Swift 名称映射,参见例如以***.com/questions/39203235/… 为例。 Swift 3 编译器不会更改您的 Objective-C 文件中的任何内容,它仅适应 Swift 方面的 Swift 3 命名约定。 @MartinR 谢谢……是的,这行得通……但在这种情况下,我真的不想为这种方法这样做,而且我绝对不认为我应该这样做到。 无论如何,看看 ObjC 接口和 Swift 映射的(最小)自包含示例会很有帮助。 您可以查看 C/Objective-C 标头的“生成的接口”,请参阅developer.apple.com/library/content/qa/qa1914/_index.html 以获取说明。 【参考方案1】:

翻译过程在

中有详细描述 SE-0005 Better Translation of Objective-C APIs Into Swift

与您的问题相关的部分是(强调我的):

从方法的基本名称中删除封闭类型的匹配项,以便 只要匹配开始于动词之后。例如,

extension UIViewController 
  func dismissViewControllerAnimated(flag: Bool, completion: (() -> Void)? = nil)

变成:

extension UIViewController 
  func dismissAnimated(flag: Bool, completion: (() -> Void)? = nil)

据我所知,这种修剪算法在 StringExtras.cpp(并使用了很多启发式方法), 和PartsOfSpeech.def 包含被视为动词的单词列表,例如

VERB(dismiss)
VERB(read)
VERB(send)

不是VERB(sent)。这就解释了为什么——稍微简化你的例子——

@interface DeliveryInfo : NSObject
-(void)readDeliveryInfoItems;
-(void)sentDeliveryInfoItems;
@end

变成

open class DeliveryInfo : NSObject 
    open func readItems()
    open func sentDeliveryInfoItems()

类型名称在动词“read”之后被删减,但不在 非动词“发送”。 (您可以通过更改第二种方法来验证 名称为sendDeliveryInfoItems,然后映射到sendItems()。)

您可以使用NS_SWIFT_NAME 覆盖映射:

-(void)readDeliveryInfoItems NS_SWIFT_NAME(readDeliveryInfoItems());

【讨论】:

编译器无法判断您的意思是“阅读”(动词 to read 的过去分词)而不是主动动词。愚蠢的英语使那个词的时态相同...;)+1 NS_SWIFT_NAME 如果您想保留“read”的较长结构或“sent”的较短结构。 @rickster: 显然编译器没有仔细listen,“read”和“read”的发音不一样吗? 好点。你应该提交一个错误......我敢打赌Apple的可访问性人员会想要正确处理它。到那时,我想解决方法是对所有标识符使用 IPA。 @MartinR 非常感谢您提供的信息...非常有用。【参考方案2】:

粗略地说(我过于简单化了),如果方法名称上的后缀是与返回类型匹配的动词对象,则删除后缀。

一个更简单的例子是一个名为 readString 的方法,它返回一个 NSString。

您的方法属于这些参数范围内(我告诉过您我过于简单,但您可以粗略地看到这是如何正确的),所以您得到了治疗。

就我个人而言,我认为这是一个错误,特别是因为在某些情况下,更改可能会导致名称冲突并使调用方法不可能(尤其是当 Objective-C API 不是你的并且你不能改变它)。举个例子,看看这个问题:Swift 3 (Omit Needless Words) causing two functions to have the same name

【讨论】:

以上是关于转换为 Swift 3 重命名了我自己的 Objective-C 方法的主要内容,如果未能解决你的问题,请参考以下文章

PromiseKit 3 for Swift2 中的“when”是不是已重命名?

将图像从 URL 保存到库,重命名并使用 Swift 共享它

将函数转换为 Swift 3 的奇怪问题

更新到 Swift 3 破坏了我的 swifty json 代码

Swift UIAlertController 文件重命名操作

获取“无法打开应用程序,因为您无权查看它。 “将项目代码从swift 2.2转换为swift 3.0之后