Sobes.tech
Middle

Πώς αποτρέπετε τις διαρροές μνήμης στα έργα σας;

sobes.tech AI

Απάντηση από AI

Χρησιμοποιώ διάφορες προσεγγίσεις:

  1. ARC (Αυτόματη Αρίθμηση Αναφορών): Είναι ο κύριος μηχανισμός διαχείρισης μνήμης στα Swift και Objective-C. Μετράει αυτόματα τις αναφορές σε αντικείμενα και τα απελευθερώνει όταν ο αριθμός των αναφορών φτάσει το μηδέν.
  2. Αποφυγή κύκλων ισχυρών αναφορών: Αυτή είναι η πιο συνηθισμένη αιτία διαρροών μνήμης. Χρησιμοποιώ αναφορές weak ή unowned για να σπάσω τους κύκλους. Αυτό συμβαίνει συχνά όταν εργάζομαι με delegates και closures.
  3. Εργαλεία προφίλ: Χρησιμοποιώ τακτικά εργαλεία από το Xcode, όπως τα Instruments (Allocator, Leaks), για την ανίχνευση διαρροών.
  4. Έλεγχος closures: Ελέγχω προσεκτικά τις closures, ειδικά κατά την καταγραφή του self, χρησιμοποιώντας λίστες καταγραφής [weak self] ή [unowned self].
  5. Αποσύνδεση από ειδοποιήσεις: Αποσυνδέομαι από το NotificationCenter και τους παρατηρητές KVO κατά την καταστροφή αντικειμένων.
  6. Διαγραφή παρατηρητών και χρονομετρητών: Απενεργοποιώ και μηδενίζω τους ακυρωμένους χρονομετρητές και διαγράφω τους παρατηρητές όταν δεν χρειάζονται πλέον.
  7. Διαχείριση πόρων: Διαχειρίζομαι σωστά πόρους όπως αρχεία, sockets και βάσεις δεδομένων, κλείνοντάς τους και απελευθερώνοντάς τους εγκαίρως.
  8. Ανασκοπήσεις κώδικα: Πραγματοποιώ τακτικά ανασκοπήσεις κώδικα, συμπεριλαμβανομένων για την ανίχνευση πιθανών προβλημάτων διαχείρισης μνήμης.

Παράδειγμα χρήσης [weak self] σε closure:

class DataFetcher {
    var completionHandler: (() -> Void)?

    func fetchData() {
        // Χρήση weak self για την αποφυγή ισχυρού κύκλου
        DispatchQueue.global().async { [weak self] in
            // Προσομοίωση λήψης δεδομένων
            sleep(1)

            DispatchQueue.main.async {
                // Έλεγχος για nil πριν από τη χρήση του self
                self?.completionHandler?()
            }
        }
    }
}

class ViewController {
    var fetcher: DataFetcher?

    func setupFetcher() {
        fetcher = DataFetcher()
        fetcher?.completionHandler = {
            // Εδώ, το self μπορεί τώρα να είναι αδύναμο αν ο fetcher εξακολουθεί να υπάρχει
            print("Δεδομένα λήφθηκαν στο ViewController")
        }
    }

    deinit {
        print("Το ViewController αποδεσμεύτηκε")
    }
}

Παράδειγμα χρήσης weak για delegate:

protocol DataProcessorDelegate: AnyObject { // AnyObject διασφαλίζει τον τύπο αναφοράς και αποτρέπει ισχυκούς κύκλους με τύπους τιμών
    func processData(_ data: String)
}

class DataProcessor {
    weak var delegate: DataProcessorDelegate? // Χρήση weak για delegate

    func process(_ data: String) {
        delegate?.processData(data)
    }
}

class AnotherViewController: DataProcessorDelegate {
    let processor = DataProcessor()

    init() {
        processor.delegate = self
    }

    func processData(_ data: String) {
        print("Επεξεργασία δεδομένων: \(data)")
    }

    deinit {
        print("AnotherViewController αποδεσμεύτηκε")
    }
}