I'm defining a protocol in Swift language, and this protocol will be used in both Objective-C and Swift projects.

Its first version is as follows:

public protocol DataCodable {
    func encode() -> Data?
    func decode(from data: Data) -> Self?
}

Since it cannot be exported to Objective-C code, I have to rewrite it as:

@objc public protocol NSDataCodable {
    func encode() -> NSData?
    func decode(from data: NSData) -> Self?
}

Now I have two problems:

  1. DataCodable is only available in Swift.
  2. NSDataCodable can only be applied to NSObject subclasses.

If I keep both protocols, I have to specify Any to the data type I hold:

public class MyClass {
    var data: Any?  // DataCodable or NSDataCodable
}

Is there any best practices to solve problems like this?

1

There are 1 best solutions below

1
On

I don't claim it to be any of the best practices, but...

I had a similar problem some years ago and ended up using two protocols and a wrapper for the Objective-C one: https://lazarevzubov.medium.com/compatible-with-objective-c-swift-code-e7c3239d949

Something like this:

import Foundation

protocol DataCodable {
  func encode() -> Data?
  func decode(from data: Data) -> Self?
}

@objc(DataCodable) protocol NSDataCodable {
  func encode() -> NSData?
  func decode(from data: NSData) -> Self?
}

final class NSDataCodableWrapper: DataCodable {

  private let wrappee: NSDataCodable

  init(_ wrappee: NSDataCodable) {
    self.wrappee = wrappee
  }

  func encode() -> Data? {
    wrappee.encode() as Data?
  }
  func decode(from data: Data) -> NSDataCodableWrapper? {
    if let wrapee = wrappee.decode(from: data as NSData) {
      return NSDataCodableWrapper(wrapee)
    }
    return nil
  }

}

public class MyClass {
  var data: DataCodable?
}

MyClass.data can have either a Swift implementation of DataCodable or an Objective-C implementation of NSDataCodable wrapped with NSDataCodableWrapper.