I’m trying to unit test a Swift class that depends on an Objective-C class. Call these SwiftClass
and ObjcClass
.
I created a protocol that contains the methods/properties of ObjcClass
that SwiftClass
needs. I created a stub (call it ObjcClassMock
) that implements those methods and properties. So I tried to do this:
// ObjcClass is in its own .m and .h files somewhere...
// In Swift:
protocol ObjcClassProtocol {
func doStuff()
}
class ObjcClassMock: ObjcClassProtocol {
func doStuff() { /* sike, actually do nothing */ }
}
class SwiftClass {
let objcClass: ObjcClassProtocol
// default to ObjcClass's singleton for compatibility with older code
init(objcClass: ObjcClassProtocol = ObjcClass.shared()) { ... }
}
// In tests:
func testSwiftClass() {
let swiftClass = SwiftClass(objcClass: ObjcClassMock())
}
Now the issue here is that ObjcClass
does not implicitly conform to this new protocol, even though it does contain all methods and properties that the protocol requires, which I guess makes sense. Force casting it to any ObjcClassProtocol
crashes at runtime (Could not cast value of type ObjcClass to ObjcClassProtocol
– I guess that also makes sense).
From what I see, I have a couple of options:
- Make
ObjcClass
conform toObjcClassProtocol
explicitly. I’m not that familiar with Objective-C, so I may be missing something here, but this seems nontrivial. In particular it seems like it would require segregating the protocol methods into their own block.ObjcClass
is also used in other places, and there is nothing that groups these particular methods together other than the fact that they are whatSwiftClass
happens to need, so I do not want to do that. (The project structure is a mess but it is what it is.) If this was Swift I could just addclass ObjcClass: ObjcClassProtocol
toObjcClass
‘s declaration and not change anything else. Can I do something similar in Objective-C? - Giving up Swift’s type safety somehow and using Objective-C dynamic dispatch. Haven’t really figured out how this might work yet. I assume it is possible but I don’t like the idea of giving up type safety.
- Perhaps other, more esoteric stuff, like type erasure
It feels like I’m barking up the wrong tree. I’m quite new to interoping between Swift and Objective-C so it feels like there is something obvious I’m missing. Surely there is an easier way to do what I want?