I have a set of classes forming a decorator pattern so that I can do some layered caching. I have an abstract class which provides the core processing of images and contains a number of overridable functions where implementations can add their individual processing.
When saving an image I have the following code:
func cacheImage(_ key:String, image:UIImage?) {
if let image = image {
saveImage(key, image:image)
} else {
deleteImage(key)
}
backingCache?.cacheImage(key, image:image)
}
func saveImage(_ key:String, image:UIImage) {}
func deleteImage(_ key:String) {}
This is where it gets weird. When compiled for Release, this code will generate an EXC_BAD_ACCESS. Tracing it with Zombies on shows messages being sent to UIImage instances after they have been deallocated.
If I attempt to get more information by compiling with the Debug configuration, the EXC_BAD_ACCESS stop occurring. Making it very difficult to debug.
I've found that if I add a print(...)
statements like this:
func deleteImage(_ key:String) {
print("Abstract delete image")
}
the EXC_BAD_ACCESS goes away.
My current theory is that without the print(...)
, Swift is aggressively de-allocing the image instances. I also remember reading something about Debug delaying ARC's garbage collection which would explain why the EXC_BAD_ACCESS doesn't occur in debug.
I've also now found that changing the method signature to:
open func deleteImage(_ key:String) {}
Also removes the EXC_BAD_ACCESS.
Can anyone give a more detailed explanation of why the EXC_BAD_ACCESS zombies are occurring? I can't see why in the first place.
I have faced
EXC_BAD_ACCESS
in my project when I was trying to set@Published
var. I have solved it by wrapping it with: