OlivaresF OlivaresF - 6 months ago 92
Swift Question

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)

Answer

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.

Comments