I'm trying to use a Swift class in a mostly Objective-C project. This revolves around UIContentConfiguration
for use with UITableViewCell
.
Here's my Swift code:
@objc class MyCellConfiguration: NSObject, UIContentConfiguration {
let label: String
@objc init(label: String) {
self.label = label
}
func makeContentView() -> UIView & UIContentView {
return MyCellContent(self)
}
func updated(for state: UIConfigurationState) -> Self {
return self
}
}
class MyCellContent: UIView, UIContentView {
// Implementation of this class is not relevant to the question
}
When I try to setup the cell in some Objective-C code, I get a compiler warning. If I ignore the warning, the app hangs at runtime when the code is reached.
Here's the Objective-C code:
#import "MyApp-Swift.h" // The bridging header is being imported
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:key forIndexPath:indexPath];
MyCellConfiguration *config = [[MyCellConfiguration alloc] initWithLabel:@"Some Label"];
cell.contentConfiguration = config; // warning here
The compiler warning I receive is:
Assigning to 'id<UIContentConfiguration> _Nullable' from incompatible type 'MyCellConfiguration *__strong'
Why doesn't the compiler recognize that MyCellConfiguration
conforms to the UIContentConfiguration
protocol in the Objective-C code?
Swift code recognizes the conformance just fine. For example, the following compiles without issue:
let cell = UITableViewCell(style: .default, reuseIdentifier: "foo")
cell.contentConfiguration = MyCellConfiguration(label: "foo")
I'm using Xcode 15.0 on macOS 13.6.1.
Some observations:
UIContentConfiguration
doesn't have an Objective-C version that you can choose using the "Language: Swift" selector. The Objective-C version is here.UIContentConfiguration
doesn't inherit NSObjectProtocol
, like other Objective-C protocols do, when they are imported into Swift.UIContentConfiguration
has a makeContentView
method that returns an intersection type, which cannot be represented in Objective-C. (The Objective-C version returns __kindof UIView<UIContentView> *
)These all suggest that UIContentConfiguration
in Swift is an entirely different protocol from its Objective-C version. Just conforming to it in Swift doesn't mean you conformed to it in Objective-C.
You can also see a similar pattern in other related types like UIContentView
and UIConfigurationState
.
In fact, try setting contentConfiguration
to an instance of MyCellConfiguration
in Swift and see what happens on the Objective-C's side. Try printing out [cell.contentConfiguration class]
in Objective-C. The output is not MyCellConfiguration
!
All of that is to say, you have to re-implement the Objective-C version of UIContentConfiguration
in Objective-C, or you can just add a method like this in Swift:
@objc
func addToCell(_ cell: UITableViewCell) {
cell.contentConfiguration = self
}
UITableViewCell *cell = ...;
MyCellConfiguration *config = [[MyCellConfiguration alloc] initWithLabel:@"Some Label"];
[config addToCell:cell];