matt
matt

Reputation: 1984

Implement protocol partially in Objective C and partially in Swift

Can I implement a protocol partially in Objective C and partially in Swift?

I have an existing Objective C class that's declared like this in the .h file.

@interface SetupViewController : UIViewController <UITableViewDataSource> {
    // etc.
}

The corresponding .m file implements the UITableViewDataSource protocol. Now I want to rewrite some of these methods in a Swift extension. But I was hoping not to have to rewrite all of them in Swift right now. (This is just an example snippet, the actual class is much longer.)

@implementation SetupViewController

// I want to rewrite this method in Swift
/*
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2; 
}
*/

// I don't want to rewrite this method in Swift yet
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {    
    // lots of code
}

So I moved one of the methods out of the Objective C file into my extension, like this:

@objc extension SetupViewController {
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // new, more involved code
    }
}

but this won't compile. I get an error saying Method 'tableView(_:numberOfRowsInSection:)' with Objective-C selector 'tableView:numberOfRowsInSection:' conflicts with previous declaration with the same Objective-C selector. But I don't have the numberOfRowsInSection method in the Objective-C file any more, I took it out.

It seems like merely putting the UITableViewDataSource in the .h file makes the Swift extension think that there are already methods implemented to fulfill the protocol.

I have also tried declaring the extension as @objc extension SetupViewController: UITableViewDataSource and removing it from the .h file, but that fails because the extension doesn't implement the protocol by itself.

Upvotes: 6

Views: 404

Answers (1)

Cristik
Cristik

Reputation: 32782

When building a project that has mixed Swift+Objective-C code, this is a brief summary of what happens:

  1. the bridging header is processed
  2. the Swift files are compiled
  3. the Objective-C files are compiled

The error you see occurs at step #2, at this point the compiler sees that the Objective-C class conforms to UITableViewDataSource, thus it assumes that the Objective-C code implements the tableView(_:numberOfRowsInSection:) method, thus it sees a conflict since the Swift code also implements the method.

The source of the problem is the fact that you are trying to implement some of the protocol methods in Objective-C, and some in Swift, and this is not possible, you need to either implement all the non-optional methods of the protocol either in Swift, or Objective-C.

If you really want to go this road, a possible solution would be to move the protocol conformance on the Swift side, and declare all the other methods in the Objective-C header as public methods of that class. But this might cause other problems along the way.

Upvotes: 2

Related Questions