mickm mickm - 1 year ago 46
Swift Question

Swift doesn't recognize method from Obj-C class

I'm working in Swift 3, taking pieces of a similar app that builds and runs under Swift 2.3 Xcode 7. We are developing a new app with some of the same functionality. Some of this is in an external library.

In the 2.3 project, I have a file:

#import <Foundation/Foundation.h>
#import <UIKit/UIImage.h>

@interface MMOCR : NSObject {


-(NSString*) doOCRAtImage:(UIImage*)scannedImage;


That file is included in the bridging header file, and it compiles and runs. This is the code:

let mmocr = MMOCR()
result = mmocr.doOCRAtImage(croppedImage)

But in my new project, I'm getting this:

'doOCRAtImage' has been renamed to 'do(at:)'

So it recognizes the class, but not the method. Is this a change from 2.3 to 3? I haven't yet converted and compiled the old project, so I don't know if this compiles under 3 and Xcode 8.

Rob Rob
Answer Source

It does recognize your method, but it's applying Swift 3's new naming conventions. So, when you call this Objective-C method, you simply want to follow the guidance of that error message and call it as do(at:):

result = mmocr.do(at: croppedImage)

For more information, see SE-0005: Better Translation of Objective-C APIs Into Swift or WWDC 2016 video Swift API Design Guidelines.

By the way, if you can edit the @interface (i.e. if MMOCR was your own class), you can override the Swift name with NS_SWIFT_NAME:

- (NSString*) doOCRAtImage:(UIImage *)scannedImage NS_SWIFT_NAME(doOCR(at:));

Then, you'd do:

let result = mmocr.doOCR(at: croppedImage)

Personally, if MMOCR was your own class, I might be tempted to rename doOCRAtImage: entirely, perhaps to something like:

- (NSString*) recognizeTextInImage:(UIImage *)scannedImage;

Then, the Swift 3 code would be:

result = mmocr.recognizeText(in: croppedImage)

This is a more dramatic change than just using NS_SWIFT_NAME, but it might yield more intuitive code in both Objective-C and Swift 3.

If this MMOCR is a third-party library that you can't easily to modify, you can always define your own extension to provide this method an alternative, more logical name, e.g.:

extension MMOCR {
    func recognizeText(in image: UIImage) -> String {
        return self.do(at: image)

Then you can do:

result = mmocr.recognizeText(in: croppedImage)

Obviously, feel free to chose whatever name you want. But this way, you can use this more logical name throughout your code rather than the cryptic do(at:) syntax.

Personally, I'd submit an enhancement request to the provider of this MMOCR class, asking them to provide a more logical Swift 3 interface (either with NS_SWIFT_NAME or by renaming the method), but the extension is a way to have an elegant interface with their API until such time that they revisit this themselves.