1

I have an app that is constantly reading data from my server and updating the data in the UI. It pulls quite a bit of data, builds some data structures, and then passes the information to the UI. The code below shows how I am collecting the data:

class Server {
    private var units: [Unit] = []

    ...

    init {
        // I pull data from a firebase realtime database here using the observe method
        // which triggers the callback everytime the data changes
        // 'data' is a big dictionary of dictionarys  which will be sorted into objects
        FirebaseDatabaseHandler.getServerInfo(serverAddress: address, callback: { data in

            // Because its a lot of data sorting it is hefty so I do this on a background thread
            // 'updateQueue' is a single static DispatchQueue that I create in AppDelegate for now
            AppDelegate.updateQueue.async {

                // here I create an array of data objects using the JSON I pulled from firebase
                // then I set the "units" variable of this object and call my update callback
                // which triggers a UI update on the main thread
                if let unitData = (data?["units"] as? [String:Any]) {
                    var unitsArray = [Unit]()
            
                    for key in unitData.keys {
                        unitsArray.append(Unit(address: key.base64Decode, data: unitData[key] as! [String:Any]))
                    }
            
                    self.units = unitsArray
                    self.updateCallback()
                }
            } 
       })
   }
   
   ...

The above code works fine, however the memory is constantly building and not being properly freed, after running for ~10-20 minutes the app builds up to 2GB of memory and crashes from running out of memory.

If I get rid of the AppDelegate.updateQueue.async { } and just let this code run on the main thread, the memory DOES get cleared and there are no crashes, the memory stays around 50-200mb, however if I do this the UI is essentially permanently frozen due to how much processing is happening on the main thread

Ive tried using the debugger to watch the size of my units array and my Server object, but neither grow in size no matter how long the app is running.

Is there anything I can do to debug this, or any reason why the memory wont get cleared when I run it from a background thread?

Quinn
  • 7,072
  • 7
  • 39
  • 61
  • Have you tried using Instruments to debug the memory behavior of your application? (https://developer.apple.com/videos/play/wwdc2019/411/) – Scott Thompson Oct 20 '21 at 22:46
  • I try creating your problem with a sample project, running on Global background thread, still get de allocate, can't reproduce your problem – AchmadJP Oct 21 '21 at 02:54
  • @AchmadJP I will see if i can come up with an easy way to reproduce... maybe ill find the issue in doing so anyway :P thanks for the effort – Quinn Oct 21 '21 at 14:16

1 Answers1

0

Add [weak self]:

FirebaseDatabaseHandler.getServerInfo(serverAddress: address, callback: {[weak self] data in

    AppDelegate.updateQueue.async { [weak self] in

Note that you will need to make some more adjustments because self would become optional.

Arik Segal
  • 2,963
  • 2
  • 17
  • 29
  • Just tried this, still seem to be having the same issue - will attempt to create a simple way to reproduce it – Quinn Oct 21 '21 at 14:18