Xcode 8 Warning "Instance method nearly matches optional requirement"
Asked Answered
A

10

32

I converted my (macOS) project to Swift 3 in Xcode 8 and I get the following warnings with several delegate methods I implement in swift classes:

Instance method 'someMethod' nearly matches optional requirement of protocol 'protocolName'

I get this for several NSApplicationDelegate methods like applicationDidFinishLaunching and applicationDidBecomeActive:

enter image description here

But also for implementations of tableViewSelectionDidChange: enter image description here

enter image description here

I used code completion to insert the method signatures and also tried copying them from the SDK-headers to rule out typos. The warnings just don't disappear and the methods are never called.

What am I missing here?

Alfilaria answered 14/9, 2016 at 16:47 Comment(3)
Simply change NSNotification to Notification for the first method, although your tableViewSelectionDidChange implementation compiles fine for me (warning free). Maybe try cleaning your build folder?Syne
@Syne Switching to Notification had no effect (I adjusted the screenshot in the question accordingly). I also did a clean and deleted the Derived Data folder.Alfilaria
I got this error with code that was copy-and-pasted from Apple's own iOS development with Swift tutorial. In my case this info was what saved me: aplus.rs/2016/… I.e., type in the func name manually and let intellisense provide the current correct parameters.Archeology
S
20

After hours of searching I found this - Swift 3 ObjC Optional Protocol Method Not Called in Subclass

You can workaround the bug by prefixing the objective-c declaration on the function

@objc(tableViewSettingsDidChange:notification:)
func tableViewSettingsDidChange(_ notification:Notification)
Scrawny answered 22/9, 2016 at 12:20 Comment(4)
The workaround works! The warning will stay, but it is now safe to ignore it as the method will get called.Switchblade
The workaround worked great for the URLSession:task:didCompleteWithError: method, whish seems to still remain problematic in Xcode 8.2.1.Herschel
I am trying to use this in xCode 8.3 and it no longer works for URLSession:task:didCompleteWithError, (I get error "method cannot be marked as @objc because the type of the 3rd parameter cannot be represented in Objective-C). I need to get this callback, any ideas?Pachton
This is still happening in Xcode 10.1 and this workaround just helped our whole iOS team from going bananas.Ewe
A
29

We contacted Apple Developer Technical Support (DTS) with this issue. They replied that this is a bug in Xcode 8.

We submitted a bug report and hope for a quick update. (Apple Bug Report ID: 28315920).

If you experience a similar issue, please also file a bug report (referring to ours) so the Apple engineers see its not a single case.


Update for Xcode ≥ 8.1

The problem seems fixed now, at least for the delegate methods we are using in our project.

Alfilaria answered 16/9, 2016 at 6:57 Comment(13)
Done. Apple Bug Report ID: 28383728. Is it safe to ignore the warning?Hibbs
@Hibbs No, the methods will never be called.Alfilaria
submitted 28921384Madrigalist
Thanks. I have been looking at the issue . You saved me time,Prado
I re-approached converting my project to Swift 3 and I can confirm that the issue is solved in XCode 8.1Alfilaria
My ID: 29691831. What a terrible error! And since September! I am having an issue with the XMLParserDelegateLineal
I have updated to xCode 8.2 and I still have the issue :(Lineal
I am working on a Swift 3 project and had not seen this before till now. On Xcode 8.2.1. After going through my code, noticed that I only hit this issue when I had declared an extension with the same name as another class that implemented those delegate methods.Duchy
I got it in xcode9. It showed up after moving an extension that added the delegate to a new file. The solution was to take the Delegate off the extension until xcode went through and was happy, then added it back and no more errors.Dunc
I'm getting the same error in applicationDidBecomeActive in 8.3! When I click into the protocol in question the method is exactly right. So, definitely a serious bug.Canea
Using Xcode 9.2 having same problem with application(_:open:options:) function...Burnard
Using Xcode 10.1 still having this issue with func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?Swacked
If you still can't find out the solution, please see the answer below to make the method public. https://mcmap.net/q/446276/-xcode-8-warning-quot-instance-method-nearly-matches-optional-requirement-quotLampe
S
20

After hours of searching I found this - Swift 3 ObjC Optional Protocol Method Not Called in Subclass

You can workaround the bug by prefixing the objective-c declaration on the function

@objc(tableViewSettingsDidChange:notification:)
func tableViewSettingsDidChange(_ notification:Notification)
Scrawny answered 22/9, 2016 at 12:20 Comment(4)
The workaround works! The warning will stay, but it is now safe to ignore it as the method will get called.Switchblade
The workaround worked great for the URLSession:task:didCompleteWithError: method, whish seems to still remain problematic in Xcode 8.2.1.Herschel
I am trying to use this in xCode 8.3 and it no longer works for URLSession:task:didCompleteWithError, (I get error "method cannot be marked as @objc because the type of the 3rd parameter cannot be represented in Objective-C). I need to get this callback, any ideas?Pachton
This is still happening in Xcode 10.1 and this workaround just helped our whole iOS team from going bananas.Ewe
K
18

One reason you might get this error has to do with method access modifiers. For example if you didn't define the function as public. So for methods on the CLLocationManagerDelegate case, changing:

func locationManager(_ manager: CLLocationManager,
                     didChangeAuthorization status: CLAuthorizationStatus)

to:

public func locationManager(_ manager: CLLocationManager,
                            didChangeAuthorization status: CLAuthorizationStatus)

(i.e. make the method public) gets rid of the warning and the method get called as expected. Note that autocomplete doesn't put the public access modifier on the method.

Kinetic answered 31/1, 2019 at 22:45 Comment(3)
This should be the accepted answer. Most of these delegate methods are invoked from objc which does not have the same method access semantics, and requires public in order to "see" the swift method implementation.Whiz
Ran into the same issue and this fixed it.Bedazzle
That should be the accepted answer to help others to find out.Lampe
T
9

for me the problem was custom Error class
Basically I had my own class with name Error and compiler was considering delegate method as a local method

I just changed name of my own class name and it worked. So, just confirm that you don't have any class name same in the function

Tecu answered 17/1, 2020 at 11:25 Comment(3)
Thanks a lot!! You could also specify Swift.Error in the function, so that the compiler knows that it is the Swift Error and not your custom Error defined. That way don't have to rename your Error to something else.Valid
Using Swift.Error I still get a warning. Changing to NSError, though, seems to have resolved the warning.Aristocratic
just make sure you don't have any custom class with same name In the parameters of the functionTecu
S
8

Another cause of this warning when NSError is being bridged to Swift:

Given this Objective-C delegate method:

- (void)myService:(id<MYService>)myService didFailForSomeReason:(NSError *)error;

That automatically generates this Swift method:

public func myService(_ myService: MYService!, didFailForSomeReason error: Error!)

The warning was shown.

In my case the reason was that my class had it's own Error type so the signature was resolving to MyClass.Error rather than Swift.Error. The solution was to fully type the Error parameter by changing it to Swift.Error:

public func myService(_ myService: MYService!, didFailForSomeReason error: Swift.Error!)
Spathic answered 11/5, 2017 at 7:51 Comment(2)
Wow this was exactly my problemFace
Ok. I had an Error inside my object that was the delegate. So indeed the compiler was reporting this correctly since I needed Swift.Error to disambiguate.Canea
S
3

For the record, I had the same problem when implementing WKWebView's didFailProvisionalNavigation delegate method. The solution was to add the @objc declaration and change the type of the last parameter from Error to NSError:

@objc(webView:didFailProvisionalNavigation:withError:)
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
    // handle error
}
Switchblade answered 4/10, 2016 at 9:30 Comment(1)
Thank you! That works. Unfortunately it is not silencing the warning for me in xcode 8.0 (8A218a).Beastings
U
1

Here's what fixed it for me.

I was getting the same warning in some code that I was sure that I typed into the editor initially and allowed it to autocomplete. I subsequently went back and re-visted the warning and tried to just type the same function over again right after my existing function. When I entered the function name over again, my function signature changed and the parms matched up exactly with what Xcode expected and the warning was suppressed.

So if you want to do a quick sanity check, do yourself a favor and try typing in the function one more time and see if the parm types change. That might be all you need.

Undeviating answered 27/7, 2017 at 23:58 Comment(0)
F
0

Just to add clarification to this rather over complicated workaround: can anyone see why the below is not firing/working when the action is being taken?

extension AppDelegate: UNUserNotificationCenterDelegate {
    @objc(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print("RESPONSE FROM NOTIFICATION!")

        switch response.actionIdentifier {
        case "reply":
            print("Reply action received!")
        case "ignore":
            print("Ignore action received!")
        default: print("Error - Unknown action received!")
            break
        }
    }
}
Fulgurate answered 6/10, 2016 at 9:17 Comment(3)
@Alfilaria Did you change anything to make it work or ...? Many thanks for clarifying :)Fulgurate
I just changed the formatting, so the code is displayed correctly. (Code must be indented to be formatted correctly). But in my testing, adding @ objc did not make it work. I am waiting for Apple to fix it...Alfilaria
gents - Is there any update on this? Now that official version of Xcode 8 is out? I still have the same warning and various delegate methods are not called.Gielgud
A
0

This had me going around in circles. It was because I created my own Notification class. Once I changed this class name (don't refactor as it will change the objc Notification paramaters), all errors disappeared

Agate answered 27/10, 2020 at 16:43 Comment(0)
D
-1

For xcode 8.1 >= and swift 3,

add @nonobjc at the beginning of method to silence this warning.

Deserved answered 21/12, 2016 at 5:25 Comment(2)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewZambia
This solution only silences the warning. The method itself still not called. So use this answer only when you don't actually want to call the method (have no idea in what situation such an "idle" method could be needed).Herschel

© 2022 - 2024 — McMap. All rights reserved.