Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Notification Center is causing memory leak

First time poster. I am very new to Swift and coding and general, and have run into a problem I can't seem to solve.

In my code, I have two view controllers. The first view controller allows a user to view Bluetooth devices, and select a device to connect to. When the user selects a device, it segues to the second view controller, which presents temperature data from the Bluetooth device.

This all works fine and dandy, but if I segue back to the first view controller, and then select the same device again, I now receive two of the same temperature readings from the device. (The bluetooth device is receiving two of the same commands from my code and is sending two values back).

Essentially every time I segue back and forth between view controllers, it seems that another instance of the view controller is created, thus creating a memory leak. (If I segued back and forth five times I would receive five Bluetooth readings for every one time I clicked the button to receive a value)

I believe my problem lies in my creation and dismissal of Notification Center Observers, but I can't seem to figure out the correct solution.

I left out code I felt wasn't pertinent to my problem, so if I'm missing any code necessary to solve the problem let me know. Any help would be greatly appreciated!

// First View Controller

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        print("*****************************")
        print("Connection complete")
        print("Peripheral info: \(String(describing: blePeripheral))")

        //Stop Scan- We don't need to scan once we've connected to a peripheral. We got what we came for.
        centralManager?.stopScan()
        print("Scan Stopped")

        //Erase data that we might have
        data.length = 0

        //Discovery callback
        peripheral.delegate = self
        //Only look for services that matches transmit uuid
        peripheral.discoverServices(nil)

        performSegue(withIdentifier: "Go", sender: nil)
    }


    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let destination = segue.destination as! TempPage
        destination.peripheral = blePeripheral
    }



func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {

        if characteristic == rxCharacteristic {
            if let ASCIIstring = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue) {
                characteristicASCIIValue = ASCIIstring
                NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: nil)
               connectionStatus = "Connected!"
            }
        }

// Second View Controller

override func viewDidLoad() {
        super.viewDidLoad()

        //Create and start the peripheral manager
        peripheralManager = CBPeripheralManager(delegate: self, queue: nil)

        //-Notification for updating the text view with incoming text
        updateIncomingData()

    }


    override func viewDidDisappear(_ animated: Bool) {
         peripheralManager?.stopAdvertising()
         self.peripheralManager = nil
         super.viewDidDisappear(animated)
         NotificationCenter.default.removeObserver(self)

    }

    func updateIncomingData () {
        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "Notify"), object: nil , queue: nil){
            notification in

            if characteristicASCIIValue != nil
            {
            self.rawValue = characteristicASCIIValue as String
                print(characteristicASCIIValue)

            }
            self.batteryLevelLabel.text = ("\(String(batteryLevel))%")

        }

@IBAction func returnToFirstViewController(_ sender: Any) {
        navigationController?.popViewController(animated: true)
        dismiss(animated: true, completion: nil)
    }



        }
like image 923
Zac Young Avatar asked Oct 20 '25 11:10

Zac Young


1 Answers

Try capturing self as unowned or weak in the notification center callback:

    func updateIncomingData () {
        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "Notify"), object: nil , queue: nil) { [unowned self] notification in

            if characteristicASCIIValue != nil
            {
            self.rawValue = characteristicASCIIValue as String
                print(characteristicASCIIValue)

            }
            self.batteryLevelLabel.text = ("\(String(batteryLevel))%")

        }

This article might be useful: https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html

like image 68
Pavel Kozlov Avatar answered Oct 23 '25 01:10

Pavel Kozlov