Perhaps the weirdest EXC_BAD_ACCESS I've seen Swift generate

383 views Asked by At

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.

1

There are 1 answers

0
Shadi Abu Hilal On

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:

 DispatchQueue.main.async {
     // set the `@Published` var here
 }