I have a project that bridges Swift and Objective-C both ways, and:
I have a @objc protocol defined in a Swift file:
@objc protocol Plugin {
@objc func onDevicePackageReceived(np: NetworkPackage) -> Bool
}
All the classes that implement this protocol are also defined in Swift, such as:
@objc class Ping : NSObject, Plugin {
@objc func onDevicePackageReceived(np: NetworkPackage) -> Bool {
if (np._Type == PACKAGE_TYPE_PING) {
connectedDevicesViewModel.showPingAlert()
return true
}
return false
}
@objc func sendPing(deviceId: String) -> Void {
let np: NetworkPackage = NetworkPackage(type: PACKAGE_TYPE_PING)
let device: Device = backgroundService._devices[deviceId] as! Device
device.send(np, tag: Int(PACKAGE_TAG_PING))
}
}
I’ve imported the automatically generated bridging header file into the Objective-C .m
file that I would like to use the Plugin
interface in:
#import "My_App_Name-Swift.h"
The bridging header is definitely working fine since other bridged Swift code are working.
I’ve also forward declared the protocol in the Objective-C .h
header file:
@protocol Plugin;
Now, in the Objective-C .m
files, I’ve got a NSMutableDictionary, _plugins
with values that are objects of those classes defined in Swift that implement the Plugin
protocol. I want to iterate through each of those objects and call the onDevicePackageReceived(np: NetworkPackage)
function as defined in the protocol, and I plan on doing that by confirming the objects to the Plugin
protocol which has that function implemented.
for (Plugin* plugin in [_plugins allValues]) {
[plugin onDevicePackageReceived:np];
}
But it keeps throwing the error Use of undeclared identifier 'Plugin'
.
I checked the automatically generated header file and it does appear to have bridged it correctly:
SWIFT_PROTOCOL("_TtP16KDE_Connect_Test6Plugin_")
@protocol Plugin
- (BOOL)onDevicePackageReceivedWithNp:(NetworkPackage * _Nonnull)np SWIFT_WARN_UNUSED_RESULT;
@end
For further reference, the Dictionary plugins
used to be declared in Swift, where the same for loop in Swift works just fine:
for plugin in plugins.values {
(plugin as! Plugin).onDevicePackageReceived(np: np)
}
So essentially, plugins
has now be moved to Objective-C, and I’m trying to replicate this exact for loop in Object-C, with the only difference being that the protocol Plugin
and all of the classes that implement it are all declared in Swift, so they need to be properly imported to Objective-C.
2
Answers
This syntax isn’t correct for protocols in ObjC:
There are no pointers to protocol existentials. ObjC doesn’t have existential types like Swift (i.e. a box that contains a type that conforms to a protocol).
I believe you mean:
This is "an arbitrary ObjC object (
id
) that conforms to Plugin."See Working with Protocols in Programming with Objective-C for details on ObjC protocol syntax.
See Protocols as Types in The Swift Programming Language for details on Swift protocol existentials (which are not the same thing as the protocol itself).
Another option if you don’t want write objc code is create swift extension for your objc class.
For example if it’s called
LegacyPluginHolder
, add new fileLegacyPluginHolder+Extensions.swift
and create extension:In
LegacyPluginHolder.m
you can use extension like this: