Reputation: 1062
Problem
Apple made Identifiable
only available in iOS 13+. It's a super useful protocol, however I ended up using my own "Identifiable" protocol named CompatibilityIdentifiable
.
public protocol CompatibilityIdentifiable {
associatedtype Id: Equatable
var id: Id { get }
}
Question:
Is there any way to make my custom CompatibilityIdentifiable
also conform to Identifiable
on iOS 13+?
Background:
In a regular project this has no use. But in an SPM package it means a lot because I can implement the same behaviour for CompatibilityIdentifiable
as for Identifiable
without duplicating my code.
Here is an example:
extension TableViewHelper where Section: CompatibilityIdentifiable {
public func replace(sections: [Section], with animation: UITableView.RowAnimation = .automatic) {
replaceSections(with: animation) { oldSection in
return sections.first(where: { $0.id == oldSection.id })
}
}
}
If I can simply make CompatibilityIdentifiable
conform to Identifiable
I can use Identifiable
for projects that are iOS 13+
I honestly don't think this is possible unless I simply copy and paste the code like this:
@available(iOS 13, *)
extension TableViewHelper where Section: Identifiable {
public func replace(sections: [Section], with animation: UITableView.RowAnimation = .automatic) {
replaceSections(with: animation) { oldSection in
return sections.first(where: { $0.id == oldSection.id })
}
}
}
I won't be doing this as we're talking about a lot of functions. So, if there is no way, I will continue using CompatibilityIdentifiable
for my future projects and my SPMs
Upvotes: 1
Views: 209
Reputation: 32783
Unfortunately, there's no way to make your protocol inherit from Identifiable
, but only from iOS 13 and above.
The reason is you cannot have two declarations of the same protocol, one for iOS 12-, and one for iOS 13+.
With Objective-C protocols, this might have been possible via some #ifdef
dance, but since Identifiable
is a Swift-only protocol, and since you're targeting a Swift package, you're out of luck.
However, if you refactor your code a little bit, you might be able to support both Identifiable
, and CompatibilityIdentifiable
with less duplication:
extension Array where Element: CompatibilityIdentifiable {
func firstWithSameId(as other: Element) {
first(where: { $0.id == other.id })
}
}
extension Array where Element: Identifiable {
func firstWithSameId(as other: Element) {
first(where: { $0.id == other.id })
}
}
extension TableViewHelper {
// mind the `internal` access modifier here (explicitly written)
internal func replaceSection(with animation: UITableView.RowAnimation, replacement: (Section) -> Section?) {
replaceSections(with: animation) { replacement($0) })
// or replaceSections(with: animation, secondParam: replacement)
}
public func replace(sections: [Section], with animation: UITableView.RowAnimation = .automatic) where Section: CompatibilityIdentifiable {
replaceSections(with: animation, replacement: sections.firstWithSameId)
}
@available(iOS 13, *)
public func replace(sections: [Section], with animation: UITableView.RowAnimation = .automatic) where Section: Identifiable {
replaceSections(with: animation, replacement: sections.firstWithSameId)
}
}
Even if the two public functions looks the same, they have only one line of code, which is easier to grasp in the economy of code duplication.
Also there's more code than by simply copy+pasting, however the two Array
extensions might be usable in other context too.
Upvotes: 1