6

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)

olivaresF
  • 1,369
  • 2
  • 14
  • 28
  • what do you mean swift header file? You should create Bridge class and import your `AppDelegate.h` there – haik.ampardjian May 09 '16 at 18:49
  • Sorry, that's exactly what I meant. I've edited the question to reflect this. – olivaresF May 09 '16 at 19:35
  • try `override func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {` – haik.ampardjian May 09 '16 at 19:43
  • `error: method does not override any method from its superclass override public func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)` – olivaresF May 09 '16 at 19:47
  • `conflicts with previous declaration with the same Objective-C selector` and `ObjC.AppDelegate:38:17: note: 'application' previously declared here` seem to suggest you´ve already implemented the method in your AppDelegate.m. Can you make sure that this is not the case? – Erik Johansson May 09 '16 at 20:00
  • As answered by Paulw11, it's not that (I didn't have the method implemented). It's the actual _declaration_ that's the issue. – olivaresF May 09 '16 at 23:34

1 Answers1

4

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.

Paulw11
  • 108,386
  • 14
  • 159
  • 186