it-swarm.com.de

Die Instanz wurde freigegeben, während noch wichtige Wertbeobachter registriert waren

Ich habe eine UITableView.

Hier habe ich verschiedene Zellen. Jede Zelle hat ein Modell. Mit KVO und NotificationCenter kann die Zelle das Modell auf Änderungen überprüfen. Wenn ich den ViewController verlasse, erhalte ich folgende Fehlermeldung:

An instance 0x109564200 of class Model was deallocated while key value observers were still registered with it. 
Observation info was leaked, and may even become mistakenly attached to some other object. 
Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x109429cc0> (
<NSKeyValueObservance 0x109429c50: Observer: 0x10942d1c0, Key path: name, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x10968fa00>
)

In der Zelle mache ich das, wenn die Modelleigenschaft gesetzt/geändert wird:

[_model addObserver:self
         forKeyPath:@"name"
            options:0
            context:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(modelIsInvalid:)
                                             name:@"modelIsInvalid"
                                           object:_model];

Dann im Dealloc der Zelle:

- (void)dealloc
{
    NSLog(@"DEALLOC CELL");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [_model removeObserver:self forKeyPath:@"name"];
}

In dem Modell überprüfe ich auch, wann es freigegeben wird:

- (void)dealloc
{
    NSLog(@"DEALLOC MODEL");
}

Alle Zellen werden vor allen Modellen freigegeben, aber ich bekomme immer noch diesen Fehler. Ich bin auch nicht sicher, wie ich den im Fehler genannten Haltepunkt setzen soll.

15
Johannes

Es funktioniert nicht, weil die Zellen wiederverwendet werden. Wenn die Zelle nicht mehr auf dem Bildschirm angezeigt wird, wird sie nicht freigegeben, und der Pool wird wieder verwendet.

Sie sollten Benachrichtigungen und KVO nicht in der Zelle registrieren. Sie sollten dies stattdessen in der Tabellensichtsteuerung tun. Wenn sich das Modell ändert, sollten Sie das Modell aktualisieren und sichtbare Zellen erneut laden.

7
Greg

Ich habe die Antwort gefunden. Ich kann den Thread nicht löschen, jemand hat geantwortet :) Vielleicht ist es nützlich für jemanden.

Das Problem ist, dass die UITableView die zuvor verwendete Zelle eine Zeile länger nach unten (dies wird sichtbar, wenn Sie weit genug scrollen) ausreißen.

Im Setter habe ich jetzt:

// Before we set new model
if (_model) {
    [_model removeObserver:self forKeyPath:@"name"];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"modelIsInvalid" object:_model];
}

_model = model;

[_model addObserver:self
         forKeyPath:@"name"
            options:0
            context:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(modelIsInvalid:)
                                             name:@"modelIsInvalid"
                                           object:_model];
6
Johannes

Basierend auf der akzeptierten Antwort (die korrekt ist) können Sie diese lösen, indem Sie den Beobachter von der Methode " preparForReuse " der Zelle entfernen.

Diese Methode wird vor der Wiederverwendung der Zelle beim Scrollen usw. aufgerufen. Sie haben also keine Probleme.

- (void)prepareForReuse{
    [_model removeObserver:self forKeyPath:@"name"];
}
4
Emilio

Möglicherweise ruft Ihr View Controller nicht die Dealloc-Methode auf, da die Referenz möglicherweise von jemandem angehalten wird und Ihre Dealloc-Methode nicht aufgerufen wird. Sie können Observer mit Ihrer viewDidUnload:- oder viewWillDisappear:-Methode entfernen oder Ihren Controller für die Aufbewahrung in das Instrument zurückverfolgen

0
Retro

Der beste Ort, um dies für Zellen und wiederverwendbare Ansichten zu tun, ist in willMove(toSuperiew).

override func willMove(toSuperview newSuperview: UIView?) { if newSuperview == nil { // check for nil means this will be removed from superview self.collectionView?.removeObserver(self, forKeyPath: "contentSize") } }

0
Basheer_CAD