Our old app is currently 30% Swift and 70% Objective-C.
So we had a lot of Objective-C code that was interopting to Swift
with the Swift headers.
And a lot of the time because of implicitly unwrapped optionals,
we would expect some variables to be non-nil but because for
some reason or for some edge case,
we had a nil parameter passed through that would cause lots of bugs.
And I think we had thousands and thousands of crashes in our current app
because of that interop issue in general.
And that's actually one of the reasons we decided that like going 100%
Swift is important for both our developer happiness,
because this is a much nicer code base to work with, but also for
the happiness of our users, who will be able to use a more robust product.
So the most common interoperability ability challenge I've encountered
is when I'm going from Swift to Objective-C, so
my Objective-C code is consuming my Swift code.
And the challenge I face is that all the time my Swift code, it includes structs
and enums and other constructs that are specific to Swift only, so
it's very difficult, or actually Xcode doesn't make it possible at all to
create headers for those in Objective-C.
And in order to have your Objective-C code consume that's that Swift code,
you have to create like wrapper classes that kind of shim your code from Swift
to Objective-C, which leads to like more lines of code, more files of code, and
more complexity, which was probably one of the larger reasons as to why we
decided to do a rewrite where we don't run into issues like this.
After we completed our nullability audit, it wasn't completely smooth
sailing, because we realized that our nullability audit actually exposed some
bad practices that we were doing in our Objective-C code base,
because sometimes things that shouldn't be nil ever, we were setting to nil,
just not realizing that we were.
But thankfully, with Apple's toolkit they've given us with Objective-C,
and when they introduced the nullability audit,
so the ability to do them, they'll give you warnings every time you set
something to nil that's not supposed to be nil.
And that was helpful in us improving the quality of our code base,
making it more robust by removing those warnings,
by making sure we'd never set those values to nil, or if they should be nil,
by making sure that we make them nullable.
There were actually no features that were especially difficult to port from
Objective-C to Swift.
And that's because porting anything from the Objective-C to Swift
is relatively straightforward.
Because Objective-C, when you went from Objective-C to Swift, like,
all the constructs that exist in Objective-C also exist in Swift.
So you can literally just go from a syntactical change
from Objective-C to Swift.
The point of our rewrite, though, was not to port the code like one to one,
it was to make architectural decisions that led to a more robust code base.
And that meant a lot of whiteboarding.
There were multiple correct solutions, but probably one best solution.
So it meant a lot of like just meeting as a team and
figuring out what that best solution was.
And that's where I think our brains worked the most.
And it was an engaging, but also a difficult problem to solve.
So for the most part, if I was writing a new app,
I would write it 100% in Swift, because
almost all the features that exist in Objective-C also exist in Swift.
That said, if I wanted to do something crazy like method swizzling,
I think because Objective-C's a dynamic language, I would do it in Objective-C.
That said, I don't think I'd ever be doing method swizzling if
I'm doing something the right way.
So I would probably go 100% Swift and maybe some Objective-C dependencies if
it made my life easier, but write my main product in Swift, because it gives
you all the powers of map and flat map and generics and structs, and
value types, which is very powerful that Objective-C just doesn't give you.