Converting to Swift 3 renamed my own Objective-C method

objective-c, swift, swift3

Solution

The translation process is described in detail in

- SE-0005 Better Translation of Objective-C APIs Into Swift

The relevant part for your question is (emphasis mine):

Prune a match for the enclosing type from the base name of a method so long as the match starts after a verb. For example,

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

becomes:

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

This pruning algorithm is – as far as I can see – implemented in StringExtras.cpp (and uses a lot of heuristics), and PartsOfSpeech.def contains a list of words which are considered a verb, such as

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

but not `VERB(sent)`. That explains why – simplifying your example slightly –

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

becomes

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

The type name is pruned after the verb "read", but not after the non-verb "sent". (You can verify that by changing the second method name to `sendDeliveryInfoItems` which is then mapped to `sendItems()`.)

You can override the mapping with `NS_SWIFT_NAME`:

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

Problem

I have swift classes mixed in with my Objective-C code. With Swift 2.3, everything was fine and worked as expected. I recently converted to Swift 3, and it updates several API calls because of all the renaming that occurred for Swift 3. That's fine; I get that. But what's not fine is that Swift 3 seems to have renamed a method in one of my Objective-C classes. I own the Objective-C class and I called the method what I wanted: `readDeliveryInfoItems`. But now, after converting to Swift 3, I can't call `.readDeliveryInfoItems()` anymore in my Swift class. It's telling me it has been renamed to `.readItems()`. That makes no sense. And the Objective-C class still calls the method `readDeliveryInfoItems`, so there is something under the covers going on here. I have tried renaming the Objective-C `readDeliveryInfoItems` method to `readDeliveryInfo`, building (Swift fails because it says that the `readInfo()` method doesn't exist, which is good), and then renaming the method back to `readDeliveryInfoItems`. However, when I build after this, Swift goes back to thinking the method is called `readInfo()`. I was hoping this would trick Xcode into refreshing the Swift bridging and renaming the method back to the correct name `readDeliveryInfoItems()`, but it did not. How can I fix this? UPDATE TO ADD MORE INFO The interface of my Objective-C class has this function declaration: ``` - (nullable NSArray<XMPPDeliveryInfoItem *> *)readDeliveryInfoItems; ``` But in the Generated Interface (see MartinR's comment below) for that class, the function declaration is this instead: ``` open func readItems() -> [XMPPDeliveryInfoItem]? ``` There are other functions in that class that are similar to the `readDeliveryInfoItems` function, such as this one: ``` - (nullable NSArray<XMPPDeliveryInfoItem *> *)sentDeliveryInfoItems; ``` And they look correct in the Generated Interface: ``` open func sentDeliveryInfoItems() -> [XMPPDeliveryInfoItem]? ``` So I can't figure out why I'm having this problem with only the one function.

Original source

Related problems