4

I started the migration of a project with the recommended wizard on Xcode 9 over a project that has both Objc and Swift working together.

The problem occurs when having the following UIColor extension:

extension UIColor {
    func doSomething(withAnotherColor color: UIColor) -> Bool {
        return true
    }
}

then on some Objc class:

@implementation MyView

    - (void)styleView {
        //... some code
        if ([someColor doSomethingWithAnotherColor:anotherColor]) {
            ... 
        }
    }
@end

The if statement is throwing the following error: ../MyView.m: No visible @interface for 'UIColor' declares the selector 'doSomethingWithAnotherColor:'

I tried using @objc directive both on the extension and method without luck.

Note this is a compilation error, not a warning like mentioned on other questions, like this one: How can I deal with @objc inference deprecation with #selector() in Swift 4?

Any ideas?

Omer
  • 5,470
  • 8
  • 39
  • 64
  • 3
    You need to mark the method (or extension) `@objc`; compare https://stackoverflow.com/q/44390378/2976878 – Hamish Sep 25 '17 at 16:24
  • Sorry, I tried many things including (what you mentioned) before posting the answer without luck. – Omer Sep 25 '17 at 17:35
  • @matt just modified the question explaining how this is different. – Omer Sep 25 '17 at 17:43
  • @Hamish is correct that this will not work without the `@objc`; even though you assert that you've tried it, it wasn't in the code in the question, and therefore it's going to be the first thing anyone thinks of when looking at this question, since removal of `@objc` inference is the main change in Swift 4 that would affect interaction between Swift and Obj-C. As for your particular problem, I might suggest cleaning and rebuilding the project, to force the generated header to be recreated after adding the `@objc`. – Charles Srstka Sep 25 '17 at 17:54
  • If that does not solve the problem, have a look at the generated header itself, and see if your method appears there. Also, obviously, make sure that your Objective-C source file is `#import`ing the header. – Charles Srstka Sep 25 '17 at 17:58
  • @CharlesSrstka Now that he's described the problem correctly, I can reproduce. – matt Sep 25 '17 at 18:04
  • @matt I understand rudeness is unnecessary, and I apologize for that. But I have to disagree that the question was unclear, in fact you where able to reproduce the error with the given information. But nevermind, I'm sorry if I offended you, water under the bridge. And thank you for your answer. – Omer Sep 26 '17 at 13:56
  • I agree that it's all water under the bridge, and am now on to the practical problem of what's actually causing the issue for you at this point. Again I repeat my offer to send you my test project, which compiles just fine. I'd be happy to look at _your_ project if you like, but I'm betting you wouldn't let me do that. – matt Sep 26 '17 at 14:28

2 Answers2

4

I fixed the problem by explicitly specifying the method signature in swift function's @objc annotation

// Swift codes

@objc(myNoArgFunc) // need to specify even if the obj-c method name is the same as the swift name
func myNoArgFunc() {
}

@objc(myFuncWithArg1:arg2:arg3:) // note the last :
func myFunc(_ arg1: String, arg2: String, arg3: int) {
}
teddy
  • 2,158
  • 4
  • 26
  • 34
0

In essence, @matt's solution is the right approach. On my specific case another things were happening

Here some comments:

  • There is no need to prefix the entire extension with @objc, adding the prefix to the function only did the trick.
  • As a mentioned on another comment, I tried this before posting but was not working, but since @matt suggested it I decided to delete all drived data, reopen the project and tried this again, now the problem was another thing (next point)
  • Apparently the way functions were translated from Swift to Objc has changed, I used to have:

Swift (UIColor category):

func doSomething(anotherColor: UIColor) -> Bool

In objc before the update, I was able to:

[aColor doSomething:anotherColor];

But after the update I needed to change it to:

[aColor doSomethingAnotherColor:anotherColor];

In order to keep using the function the same way in Objc, you can change the Swift function to:

func doSomething(_ anotherColor: UIColor) -> Bool

And that was whole the problem on my end. Hope this helps someone.

Omer
  • 5,470
  • 8
  • 39
  • 64