Skip to content

Instantly share code, notes, and snippets.

@SixBe
Created April 26, 2018 13:45
Show Gist options
  • Save SixBe/c0ec47335aabfad00d0f190b87bf654b to your computer and use it in GitHub Desktop.
Save SixBe/c0ec47335aabfad00d0f190b87bf654b to your computer and use it in GitHub Desktop.
import Foundation
@objc public protocol DataSourceProtocol: AnyObject {
@objc func runDataSourceRequest(_ dataSourceRequest: DataSourceRequest) -> AnyObject?
}
@objc public protocol DataSourceRequest {
var responseModel: AnyClass { get }
}
class DataSource: DataSourceProtocol {
@objc func runDataSourceRequest(_ dataSourceRequest: DataSourceRequest) -> AnyObject? {
guard let modelClass = dataSourceRequest.responseModel as? Decodable.Type else {
print("This is not working")
return nil
}
return self.runWithoutTemplate(responseModelClass: modelClass)
}
func runWithoutTemplate(responseModelClass: Decodable.Type) -> AnyObject? {
let data = """
{
"isTesting": true
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let model = try? decoder.decode(responseModelClass, from: data)
print("\(String(describing: model))")
return model as AnyObject
}
}
extension JSONDecoder {
struct DecodingHelper: Decodable {
private let decoder: Decoder
init(from decoder: Decoder) throws {
self.decoder = decoder
}
func decode(to type: Decodable.Type) throws -> Decodable {
let decodable = try type.init(from: decoder)
return decodable
}
}
func decode(_ type: Decodable.Type, from data: Data) throws -> Decodable {
let decodingHelper: DecodingHelper = try JSONDecoder().decode(DecodingHelper.self, from: data)
let decodable = try decodingHelper.decode(to: type)
return decodable
}
}
@objc class TestModel: NSObject, Decodable {
@objc var isTesting: Bool
private init(isTesting: Bool) {
self.isTesting = isTesting
}
}
@objc class TestDataSourceRequest: NSObject, DataSourceRequest {
@objc var responseModel: AnyClass {
return TestModel.self
}
}
let dataSource = DataSource()
let dataSourceRequest = TestDataSourceRequest()
let model = dataSource.runDataSourceRequest(dataSourceRequest) as? TestModel
model?.isTesting
@kschaller
Copy link

Quoting @SixBe:

I faced an interesting situation on [redacted] when converting some of our objective-C code to use Decodable Swift models. I wanted to write an adapter so I would wrap Swift classes using an @objc interface. The code [above] shows an example of how this would work.

Here DataSourceRequest and DataSourceProtocol are @objc compatible. From Objective-C I can call the @objc method runDataSourceRequest, which under the hood is going to extract the class and decode it using a JSONDecoder. Naturally the class I pass around using DataSourceRequest is in fact a Swift Decodable class, but Objective-C knows nothing about it.
In the end, apart from a few data sources, I needed to write more adapter code than for a straightforward Swift conversion so I will not pursue that approach. But I’m sure some will find it interesting. The tricky part was being able to perform the decoding on a Decodable.Type object. I found the DecodingHelper approach on SO, typically something I would not have invented myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment