Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing didRegisterForRemoteNotificationsWithDeviceToken in a Swift extension does not work

I'm trying to slowly migrate from Obj-C to Swift. My first step is to migrate small, simple methods to Swift extensions so I decided to try and migrate didRegisterForRemoteNotifications but that didn't work because it thinks the method is implemented somewhere else in my Objective-C code. It is not.

I'm using Xcode 7.3 (7D175)

Here's some reproduction steps:

  • Create a new Obj-C project.
  • Create a new empty Swift file called AppDelegate-Extension.swift. This also creates a Bridging header file.
  • Add #import AppDelegate.h to the Briding header file.
  • Go to the empty Swift file and type:

    extension AppDelegate {
    
        public func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    
        }
    }
    

This causes to compiler to complain:

method 'application(_:didRegisterForRemoteNotificationsWithDeviceToken:)' with Objective-C selector 'application:didRegisterForRemoteNotificationsWithDeviceToken:' conflicts with previous declaration with the same Objective-C selector public func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) { ^ __ObjC.AppDelegate:38:17: note: 'application' previously declared here public func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)

What am I doing wrong?

EDIT: Some suggestions that I've tried:

Add override to the method declaration so it reads override public ...

This returns the following error (in addition to the original error)

error: method does not override any method from its superclass override public func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)

like image 480
olivaresF Avatar asked Oct 18 '22 10:10

olivaresF


1 Answers

Your problem is that you can't use an extension in this way in a mixed Swift & Objective-C environment.

In Swift, you can use an extension to provide implementations for functions that have been declared in a protocol that is adopted by a class. This is the core of 'protocol-oriented-programming'

In Objective-C, a category is used to add additional functions to an existing class. When you create your Swift extension, Xcode creates a targetname-Swift.h file in the derived-data folder. Now, you can't see this file because your compile is failing, but if you change your extension slightly so that the compilation works

extension AppDelegate {
    public func application(app application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {    
    }
}

and then you look at this file you will find something like:

@interface AppDelegate (SWIFT_EXTENSION(XTNTest))
    - (void)applicationWithApp:(UIApplication * _Nonnull)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData * _Nonnull)deviceToken;
@end

Note how your extension method has been added as a category onto AppDelegate. Now, imagine what this file would look like if you had the correct form of your function (no app in the signature)

@interface AppDelegate (SWIFT_EXTENSION(XTNTest))
    - (void)application:(UIApplication * _Nonnull)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData * _Nonnull)deviceToken;
@end

This is a re-declaration of a method that is already declared in the UIApplicationDelegate protocol.

The upshot of all this is that you either need to adopt Swift on a class-by-class basis or you need to use subclassing if you want to use a function-by-function basis since there is a difference between an Objective-C category and a Swift extension.

like image 176
Paulw11 Avatar answered Nov 01 '22 16:11

Paulw11