How to use Notification.Name extension from Swift to Objective-C?
Asked Answered
U

3

40

I created an extension for Notification.Name as below:

public extension Notification.Name {
    public static let blahblahblah = Notification.Name(rawValue: "blahblahblah")
}

Now I want to use this extension in Objective-C, but it's not accessible even if its public.

How can I access and use this Swift extension in both Objective-C and Swift?

Previously I was using constant values in Objective-C, but now I'm upgrading my code and want to use this extension.

Unwept answered 18/10, 2017 at 20:19 Comment(0)
L
24

Notification.Name doesn't exist in Objective-C. And the Objective-C type NotificationName is really just an NSString. To use Swift stuff in Objective-C, the class must be available in both, and can't be a Swift struct (like Notification or String, say).

To do what you want, then, you need to have two extensions:

  • one for the Swift Notification.Name, as you have; and,
  • one for an Objective-C object (NSString, say, or perhaps NSNotification if you prefer).

1) Add an Objective-C-compatible object extension to your Swift file:

public extension NSNotification {
    public static let blahblahblah: NSString = "blahblahblah"
}

Note: in Swift 4, properties must be computed for Objective-C compatibility. That would look like:

@objc public extension NSNotification {
    public static var blahblahblah: NSString {
        return "blahblahblah"
    }
}

Note the var in the computed property: computed properties can't be immutable, so can't use let.

2) In the Objective-C file, import Xcode's generated Swift header file (below any other imports):

#import "YourProjectName-Swift.h"

Note: replace YourProjectName with the actual name of your project. So, if your project is named "CoolGameApp", the Swift header would be "CoolGameApp-Swift.h". If your project name has spaces, like "Cool Game App", replace them with dashes: "Cool-Game-App-Swift.h"

3) Rebuild the project.

Now, you should be able to access the extension in Objective-C:

[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification.blahblahblah object:self];
Leyden answered 19/10, 2017 at 16:27 Comment(3)
It worked for me. I was trying to use @objc, but it can only be used with members of classes and protocols, not for extensions. Thanks @LeydenUnwept
And one more thing, for extension NSNotification, I used let instead of var, and it worked. (obviously, it should work) so it's not necessary to use the computed property if there is a constant string. And we don't even need public static, only extension should be public.Unwept
Right, Swift 3 doesn’t require the computed property; Swift 4 does, according to the docs. And making it static means it’s available on the class rather than requiring an instance. Happy coding! (Make sure to click the checkmark to indicate my answer worked for you.)Leyden
A
76

My extension in swift file

extension Notification.Name {
    static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
}

@objc extension NSNotification {
    public static let purchaseDidFinish = Notification.Name.purchaseDidFinish
}

// OBJECTIVE-C

#import YourProjectName-Swift.h

[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(purchaseDidFinish) name:NSNotification.purchaseDidFinish object:nil];

// SWIFT
NotificationCenter.default.addObserver(self, selector: #selector(purchaseDidFinish), name: .purchaseDidFinish, object: nil)

@objc func purchaseDidFinish(notification: Notification) {
    print("purchaseDidFinish")
}

@leanne's answer was super helpful

Aurelio answered 23/1, 2018 at 12:39 Comment(4)
excellent solution ! thanks a lot ^^ however, had to add "@objc" on the second extension (NSNotification), in order to be able to use it in objc code, surely due to swift 4 objc new inference rules ;) (as mentionned in @janineanne answer)Devoir
polo987 is right. Project with "Swift 3 @objc inference" in the build settings set to OFF will need "@objc" if they want to use that property. New projects will be created with this set to OFF by default.Deflocculate
This is the best solution. I went as far as adding a protocol with for my notifications that both the Notification.Name extension and the NSNotification extension adopt. This gives me the benefit of knowing that my notifications are definitely available in both languages.Neolithic
In fact in Xcode 10 I get "Some object files have incompatible Objective-C category definitions. Some category metadata may be lost. All files containing Objective-C categories should be built using the same compiler." warning for extension on NSNotification.Schaffner
L
24

Notification.Name doesn't exist in Objective-C. And the Objective-C type NotificationName is really just an NSString. To use Swift stuff in Objective-C, the class must be available in both, and can't be a Swift struct (like Notification or String, say).

To do what you want, then, you need to have two extensions:

  • one for the Swift Notification.Name, as you have; and,
  • one for an Objective-C object (NSString, say, or perhaps NSNotification if you prefer).

1) Add an Objective-C-compatible object extension to your Swift file:

public extension NSNotification {
    public static let blahblahblah: NSString = "blahblahblah"
}

Note: in Swift 4, properties must be computed for Objective-C compatibility. That would look like:

@objc public extension NSNotification {
    public static var blahblahblah: NSString {
        return "blahblahblah"
    }
}

Note the var in the computed property: computed properties can't be immutable, so can't use let.

2) In the Objective-C file, import Xcode's generated Swift header file (below any other imports):

#import "YourProjectName-Swift.h"

Note: replace YourProjectName with the actual name of your project. So, if your project is named "CoolGameApp", the Swift header would be "CoolGameApp-Swift.h". If your project name has spaces, like "Cool Game App", replace them with dashes: "Cool-Game-App-Swift.h"

3) Rebuild the project.

Now, you should be able to access the extension in Objective-C:

[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification.blahblahblah object:self];
Leyden answered 19/10, 2017 at 16:27 Comment(3)
It worked for me. I was trying to use @objc, but it can only be used with members of classes and protocols, not for extensions. Thanks @LeydenUnwept
And one more thing, for extension NSNotification, I used let instead of var, and it worked. (obviously, it should work) so it's not necessary to use the computed property if there is a constant string. And we don't even need public static, only extension should be public.Unwept
Right, Swift 3 doesn’t require the computed property; Swift 4 does, according to the docs. And making it static means it’s available on the class rather than requiring an instance. Happy coding! (Make sure to click the checkmark to indicate my answer worked for you.)Leyden
R
5

In addition to the answers here, I had to add @objc to my NSNotification extension before my Obj-C code could see it (Swift 4).

Rolfe answered 30/3, 2018 at 19:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.