weak vs. unsave_unretained ... und warum überhaupt?

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • weak vs. unsave_unretained ... und warum überhaupt?

    Hallo zusammen,

    eine meiner Apps erzeugte einen unerwarteten Crash nachdem ich mit Xcode 13.4 eine neue Version veröffentlichte ... und ich bin auf der Suche nach einer Erklärung:

    An einer Stelle rufe ich - noch mit Objective-C - einen MFMailComposeViewController auf, welcher eine Datei vom iCloud-Drive anhängen soll. Daher benötige ich einen Block für's koordinierte Lesen, der eigentlich so aussehen sollte:

    Quellcode

    1. if ([MFMailComposeViewController canSendMail])
    2. {
    3. [...]
    4. NSFileCoordinator *coordinator = [NSFileCoordinator new];
    5. [coordinator coordinateReadingItemAtURL:mailURL options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL *url)
    6. {
    7. MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
    8. [mailController setMailComposeDelegate:self];
    9. [...]
    10. }];
    11. }
    Alles anzeigen
    Leider führte das früher zu einer Compiler-Warning Capturing 'self' strongly in this block is likely to lead to a retain cycle. Um dieses Problem zu vermeiden, nutzte ich eine schwache Referenz auf beim Zuweisen des Delegates:

    Quellcode

    1. if ([MFMailComposeViewController canSendMail])
    2. {
    3. [...]
    4. __weak typeof(self) weakSelf = self;
    5. NSFileCoordinator *coordinator = [NSFileCoordinator new];
    6. [coordinator coordinateReadingItemAtURL:mailURL options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL *url)
    7. {
    8. MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
    9. [mailController setMailComposeDelegate:weakSelf];
    10. [...]
    11. }];
    12. }
    Alles anzeigen
    Das Ganze lief jahrelang. Nun crashte die App hier und ich stellte fest, dass der ursprüngliche - mir auch korrekt erscheinende - Code keine Warnung mehr erzeugt. Eigentlich konnte es auch m. E. keinen Retain-Cycle geben, da der MailCompose-VC auch nur so lange leben kann, wie der aufrufende VC. Oder was verstehe ich falsch?


    Um die Verwirrung komplett zu machen, besteht das gleiche Problem - die ursprüngliche Warnung und nun der Crash - auch bei Blöcken eines UIAlertControllers mit einem Text-Feld. Dort reicht self jedoch nicht, aber der (meines Wissens unsichere) Weg über __unsafe_unretained funktioniert.

    Ich bin maximal verwirrt und befürchte die nächste Falle in Zukunft, auch wenn die App jetzt läuft.

    Wie geht ihr mit der obigen Compiler-Meldung um, wenn ihr in einem Block eine Referenz auf das aufrufende Objekt benötigt (bei mir MailCompose- bzw. TextField-Delegate? Und wieso sollte ich "__unsafe_unretained" verwenden, wenn gerade dort doch die Gefahr eines "in die Walachei"-zeigenden Pointers besteht?

    Für jede Erklärung dankbar, Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Ich habe hier noch einen Artikel gefunden, in dem am Anfang des Blocks eine strong Referenz auf die weak definierte erstellt wird, um so deren Existenz während der Blockausführung sicherzustellen.

    Erscheint mir zwar als konsequenter Folgeschritt (und würde ich auch lieber als die __unsave_unretained-Variante verwenden), aber warum dies überhaupt notwendig sein sollte, übersteigt mein Verständnis von ARC und Retain-Counts. Und warum dann manchmal und nicht immer bei z. B. Delegate-Zuweisungen in Blocks?

    Verwirrt, Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.