Changing from subclass to base class invalidates protocol implementation ??

Hi,


I want to write some reuable code that implements a protocol. It all went fine when it was added in an extension to ViewController, my own subclass of UIViewController, but when I changed the extension to UIViewController, I get the error message:
Instance method 'adViewDidReceiveAd' nearly matches optional requirement 'adViewDidReceiveAd' of protocol 'GADBannerViewDelegate'
against both the methods implemented (with the correct function name), and the code stops getting run.
There was something like this back in XCode 8 (https://stackoverflow.com/questions/39495773/xcode-8-warning-instance-method-nearly-matches-optional-requirement )but they were saying it had been fixed. I am using version 10.0 (10A255).
Here is the code that gives that error message:

extension UIViewController: GADBannerViewDelegate {
    
    // From GADBannerViewDelegate (fully optional protocol)
    
    @objc func adViewDidReceiveAd(_ bannerView: GADBannerView)
    {
        bannerView.isHidden = false
    }
    
    @objc func adView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: GADRequestError)
    {
        bannerView.isHidden = true
        print("AdMob error:", error.localizedDescription)
    }
   

Simply changing UIViewController to ViewController makes it work.
I can't think of any reason that this shouldn't work as is. Can anyone give some certainty on what is up here?
It may be relevant that the protocol used here is defined in Objective-C, and the methods are optional. I have added @objc as an attempt to get it to work, but that made no difference.
TIA
Mark

Replies

I did the test with similar set up: MyViewController, a subClass of UIViewController, a protocol extension for MyViewController with 2 func.

Then changed to UIViewController.

All works fine in both cases.


Did you do a clean build forlder ?


Do you get the same error for the second func (probably yes).


Could you post the protocol definition.

Thanks for looking into that.
Yes, I have done a clean build folder, several times in fact. The warning comes right back.
And yes, I get the same error for both functions.
I think the compiler just likes the way you move 😉

The protocol involved is described here:
https://developers.google.com/ad-manager/mobile-ads-sdk/ios/api/reference/Protocols/GADBannerViewDelegate
The code is here: (If this is not allowed to be posted on this forum, please inform me so that I can take it down.

//
//  GADBannerViewDelegate.h
//  Google Mobile Ads SDK
//
//  Copyright 2011 Google Inc. All rights reserved.
//

#import 

#import 
#import 

@class GADBannerView;

GAD_ASSUME_NONNULL_BEGIN

/// Delegate methods for receiving GADBannerView state change messages such as ad request status
/// and ad click lifecycle.
@protocol GADBannerViewDelegate

@optional

#pragma mark Ad Request Lifecycle Notifications

/// Tells the delegate that an ad request successfully received an ad. The delegate may want to add
/// the banner view to the view hierarchy if it hasn't been added yet.
- (void)adViewDidReceiveAd:(GADBannerView *)bannerView;

/// Tells the delegate that an ad request failed. The failure is normally due to network
/// connectivity or ad availablility (i.e., no fill).
- (void)adView:(GADBannerView *)bannerView didFailToReceiveAdWithError:(GADRequestError *)error;

#pragma mark Click-Time Lifecycle Notifications

/// Tells the delegate that a full screen view will be presented in response to the user clicking on
/// an ad. The delegate may want to pause animations and time sensitive interactions.
- (void)adViewWillPresentScreen:(GADBannerView *)bannerView;

/// Tells the delegate that the full screen view will be dismissed.
- (void)adViewWillDismissScreen:(GADBannerView *)bannerView;

/// Tells the delegate that the full screen view has been dismissed. The delegate should restart
/// anything paused while handling adViewWillPresentScreen:.
- (void)adViewDidDismissScreen:(GADBannerView *)bannerView;

/// Tells the delegate that the user click will open another app, backgrounding the current
/// application. The standard UIApplicationDelegate methods, like applicationDidEnterBackground:,
/// are called immediately before this method is called.
- (void)adViewWillLeaveApplication:(GADBannerView *)bannerView;

@end

GAD_ASSUME_NONNULL_END

Cannot see any reason why it works with subclass and not the class.


If only the error message told how Instance method 'adViewDidReceiveAd' nearly matches optional requirement 'adViewDidReceiveAd' of protocol 'GADBannerViewDelegate'.


In your case, I would

- keep the protocol for subclass (but sure you did not wait for me to do this)

- file a bug report, at leaset enhancement for more detailed error message

- report bug number here to keep track.


Good luck.

I have filed bug number 45355407
https://bugreport.apple.com/web/?problemID=45355407

Here's a couple of things to try:


1. Go to the Issues navigator (Command-5) and expand the error message in the list. It should tell you the signatures of both the method you provided, and the one it's expecting. If you compare them very carefully, you should be able to spot a difference.


2. Instead of typing or pasting the Swift delegate method signature, use autocomplete. That is, type (say) "func adViewDidReceive" and press Esc if necessary to get an autocomplete list.

Thanks, I tried that, but it is still the same.