ios - Nachricht an eine nicht zugeordnete Instanz gesendet




objective-c memory-management (5)

Das schlägt Apple vor :

-(void) dealloc {
      [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Aber das ist nur der letzte Ausweg, um Beobachter zu entfernen, immer noch eine gute Angewohnheit, sie immer hinzuzufügen, um sicherzustellen, dass alles auf Dealloc sauber ist, um Abstürze zu verhindern.

Es ist immer noch eine gute Idee , den Beobachter zu entfernen, sobald das Objekt nicht mehr bereit (oder erforderlich) ist, um Benachrichtigungen zu erhalten .

Hintergrund:

Alle meine OpenTok-Methoden befinden sich in einem ViewController , der wie eine typische Master / Detail-VC-Beziehung in den Blickpunkt ViewController wird. Der DetailVC verbindet Sie je nach Ihrer Auswahl mit einem anderen Raum. Wenn ich den Zurück-Knopf drücke, um die Ansicht wegzuschneiden, bekomme ich einen Absturz (vielleicht 1 von 7 Malen):

[OTMessenger setRumorPingForeground] message sent to deallocated instance xxxxx

oder

[OTSession setSessionConnectionStatus:]: message sent to deallocated instance 0x1e1ee440

Ich habe meine unpublish / disconnect Methoden in viewDidDisappear:

-(void)viewDidDisappear:(BOOL)animated{

    //dispatch_async(self.opentokQueue, ^{
    [self.session removeObserver:self forKeyPath:@"connectionCount"];

    if(self.subscriber){
        [self.subscriber close];
        self.subscriber = nil;
    }

    if (self.publisher) {
        [self doUnpublish];
    }

    if (self.session) {
        [self.session disconnect];
        self.session = nil;
    }
    //});
    [self doCloseRoomId:self.room.roomId position:self.room.position];
}

Hier ist eine Spur:

Hier ist der DetailViewController auf Github: Link hier

Wie man reproduziert:

  1. Treffen Sie eine Auswahl aus der MasterVC, die Sie in die DetailVC führt, die sofort versucht, eine Verbindung zu einer Sitzung herzustellen und zu veröffentlichen

  2. Gehen Sie schnell zur vorherigen MasterVC zurück, normalerweise bevor die Sitzung eine Chance hatte, einen Stream zu veröffentlichen

  3. Versuchen Sie es mehrmals und schließlich wird es abstürzen.

  4. Wenn ich verlangsame und dem Publisher die Möglichkeit gebe, eine Verbindung herzustellen und zu veröffentlichen, ist es weniger wahrscheinlich, dass er einen Absturz verursacht.

Erwartetes Ergebnis:

Es sollte einfach von der Sitzung trennen / Veröffentlichung aufheben und eine neue Sitzung starten, während ich zwischen den Master / DetailVCs hin und her gehe.

Andere:

Was ist Ihre Geräte- und Betriebssystemversion? iOS 6

Um welche Art von Konnektivität handelt es sich? W-lan

Zombies aktiviert? Ja

ARC aktiviert? Ja

Delegierte auf Null gestellt? Ja, soweit ich weiß

Jede Hilfe bei der Lösung dieses Absturzes wäre sehr willkommen. Vielleicht fehlt mir etwas Grundlegendes, das ich einfach nicht sehen kann.

Es scheint, dass das OTSession-Objekt in der OpenTok-Bibliothek weiterhin Nachrichten an Objekte in dieser Bibliothek sendet, deren Zuordnung durch Wechseln der Ansichten aufgehoben wurde. Die Bibliothek verfügt über eine [Sitzung trennen] -Methode, die funktioniert, wenn Sie genügend Zeit geben, aber es dauert fast 2-3 Sekunden, und das ist eine lange Zeit, eine App zwischen Ansichten anzuhalten.

Das ist vielleicht eine blöde Frage, aber: Gibt es überhaupt irgendwelche Prozesse, die von einem bestimmten VC ausgelöst werden?


Das Schließen der Sitzung von viewWillDisappear() funktioniert, wenn Sie sicher feststellen können, dass die Ansicht viewWillDisappear() , nicht verschoben oder ausgeblendet wird. Einige Antworten schlagen vor, diesen Code in dealloc() . In Bezug auf diese Vorschläge sagt Apple,

Sie sollten versuchen, die Lebensdauer begrenzter Ressourcen mit dealloc zu vermeiden .

So, hier ist, wie Sie sicher feststellen können, dass Ihre Ansicht auftauchen wird. viewWillDisappear() wird aufgerufen, wenn die Ansicht vom Stapel entfernt oder anderweitig an anderer Stelle viewWillDisappear() wird. Dies ist der einfachste Weg, um zu bestimmen, was und dann die Veröffentlichung aufheben / trennen, wenn es wirklich gepoppt wird. Sie können dies mit isMovingFromParentViewController . Hier können Sie auch bestimmte Beobachter entfernen.

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated]

    // This is true if the view controller is popped
    if ([self isMovingFromParentViewController])
    {
        NSLog(@"View controller was popped");

        // Remove observer
        [[NSNotificationCenter defaultCenter] removeObserver:self.session];

        ...

        //dispatch_async(self.opentokQueue, ^{
            if(self.subscriber){
                [self.subscriber close];
                self.subscriber = nil;
            }

            if (self.publisher) {
                [self doUnpublish];
            }

            if (self.session) {
                [self.session disconnect];
                self.session = nil;
            }
            //});
            [self doCloseRoomId:self.room.roomId position:self.room.position];
    }
    else
    {
        NSLog(@"New view controller was pushed");
    }
}

Ref: Testen bestimmter Arten von View-Übergängen


Meistens lege ich einen solchen Code in die ViewWillDisappear, aber das ist nicht wirklich wichtig.

Ich glaube, das Problem ist, dass Ihr Sitzungsdelegat nicht auf Null gesetzt ist. Fügen Sie einfach Folgendes in Ihrer Ansicht hinzuDidDisappear:

self.session.delegate=nil;

Sie müssen [super viewDidDisappear: animate] aufrufen; am Anfang. Vielleicht wird es Ihr Problem beheben. Und bereinigen Sie Ihre Sitzung und Ihren Abonnenten mit der Dealloc-Methode:

- (void) dealloc {
    [self.session removeObserver:self forKeyPath:@"connectionCount"];

    if(self.subscriber){
        [self.subscriber close];
        self.subscriber = nil;
    }

    if (self.publisher) {
        [self doUnpublish];
    }

    if (self.session) {
        [self.session disconnect];
        self.session = nil;
    }
    [self doCloseRoomId:self.room.roomId position:self.room.position];

  //[super dealloc]; //for non-ARC
}

OpenTok hat OpenTok einen Fehler bei der Verwendung von NSNotificationCenter innerhalb von OTSession und OTMessenger Klassen. Sie können sehen, dass diese Klassen im Call-Stack durch NSNotificationCenter Aufrufe getrennt sind:

Sie können Ihr OTSession Objekt beim Dealloc manuell abmelden ( OpenTok verwendet defaultCenter ):

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self.session];
}

Sie müssen überprüfen, ob dieser Code ( dealloc ) wirklich ausgeführt wird. Wenn nicht - müssen Sie das Problem der UIViewController Freigabe beheben. Viele andere Antworten enthalten Tipps, wie Sie die UIViewController von UIViewController können.





opentok