I've used a solution with CustomTabBar
, but I ended up getting a lot of exceptions which didn't tell me anything. Every time I was getting a different error, or sometimes no error at all. For example one of the errors in a random place:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)
Or:
malloc: Incorrect checksum for freed object 0x14ce4c790: probably modified after being freed.
Corrupt value: 0xb000000000000001
malloc: *** set a breakpoint in malloc_error_break to debug
I searched for a solution and on Apple's dev-forum user eskimo advised to use Standard Memory Debugging Tools.
Zombies instrument didn't help, but Address Sanitizer helped to identify the problem at once!
Error log:
SUMMARY: AddressSanitizer: heap-buffer-overflow MyTabBarController.swift in MyTabBarController.CustomTabBar.hasBanner.setter
thread #1: tid = 0x6801d, 0x00000001089bb250 libclang_rt.asan_iossim_dynamic.dylib`__asan::AsanDie(), queue = 'com.apple.main-thread', stop reason = Heap buffer overflow
{
"access_size": 1,
"access_type": 1,
"address": 4918104816,
"description": "heap-buffer-overflow",
"instrumentation_class": "AddressSanitizer",
"pc": 4382625148,
"stop_type":
The problem was that I used an instance variable in CustomTabBar. For some reason it was causing crashes. I've switched the var to a static and it solved the problem!
Here is the working code:
class MyTabBarController: UITabBarController {
override func viewDidLoad() {
// We have to put all init logic here because:
// `UITabBarController` calls `loadView()` inside `super.init()` method,
// which causes the call to `viewDidLoad()`.
// So the `viewDidLoad()` method will be called before `init()` has finished its job.
object_setClass(tabBar, CustomTabBar.self)
CustomTabBar.hasBanner = InAppPurchaseManager.shared.activeSubscription == nil
super.viewDidLoad()
// ...
}
// ...
}
extension MyTabBarController {
class CustomTabBar: UITabBar {
// We have to use a static var `hasBanner`
// because an instance var causes a Heap Buffer Overflow.
static var hasBanner: Bool = true // <------------------- THE SOLUTION
override func sizeThatFits(_ size: CGSize) -> CGSize {
var sizeThatFits = super.sizeThatFits(size)
sizeThatFits.height = Constants.Layout.tabBarHeight + (Self.hasBanner ? 44 : 0)
return sizeThatFits
}
}
}