ARC Problem mit Speicherfreigabe

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

  • ARC Problem mit Speicherfreigabe

    Moin zusammen,

    habe eine Frage, ob ich es momentan richtig mache! Ich habe mir die Doku durchlgesen und das nicht nur einmal.
    Ich weiß, dass man bei ARC eigentlich kein "nil" nutzen muss.
    Aber anders funktioniert es nicht. Hier mein Code:

    Quellcode

    1. - (void)viewDidLoad{
    2. [super viewDidLoad];
    3. //Slideshow
    4. slideshow = [[Slideshow alloc] initWithFrame:CGRectMake(0.0, 20.0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height) setVerzeichniss:@"Grunddaten/startbilder" setDateiendung:@"png"];
    5. [self.view insertSubview:slideshow atIndex:0];
    6. }
    7. - (void)viewDidDisappear:(BOOL)animated{
    8. //Slideshow
    9. [slideshow ende];
    10. [slideshow removeFromSuperview];
    11. slideshow = nil;
    12. }
    Alles anzeigen


    Speicher am Anfang 7,9 MB, nachdem ich im NavigationController push ausführe wird ja "viewDidDisappear" ausgeführt. Speicher sinkt auf 4,5 MB.

    Wenn ich den Code aber so verändere:

    Quellcode

    1. - (void)viewDidDisappear:(BOOL)animated{
    2. //Slideshow
    3. [slideshow ende];
    4. [slideshow removeFromSuperview];
    5. }


    Hier bleibt der Speicher auf 7,9 MB.
    Mach ich irgendwas komplett falsch?

    Vielen Dank schon mal für die Antworten...
  • slideshow ist vermutlich eine Instanzvariable oder Property, auch wenn Du fälschlicherweise keinen Setter/Getter benutzt. Daher erkennst du anscheinend auch nicht, dass ARC keine Veranlassung sieht, die Slideshow Instanz nicht durch das Entfernen vom Superview zu löschen. Es gibt ja schließlich noch eine strong Reference auf das Objekt.

    Michael
  • Hier der Code von Slideshow!

    Variable ist hier:

    Quellcode

    1. @interface Startseite ()
    2. {
    3. Slideshow *slideshow;
    4. }


    Slideshow.h

    Quellcode

    1. @interface Slideshow : UIView
    2. {
    3. int zaehler;
    4. int anz_bilder;
    5. NSString *ordner;
    6. NSString *dateiformat;
    7. UIImageView *iV_slideshow;
    8. }
    9. @property (nonatomic) BOOL aktiv;
    10. -(id)initWithFrame:(CGRect)frame setVerzeichniss:(NSString *)verzeichniss setDateiendung:(NSString *)dateiendung;
    11. //Einstellung
    12. -(void)einstellung;
    13. //Start
    14. -(void)start;
    15. //Ende
    16. -(void)ende;
    17. @end
    Alles anzeigen


    Slideshow.m

    Quellcode

    1. -(id)initWithFrame:(CGRect)frame
    2. setVerzeichniss:(NSString *)verzeichniss
    3. setDateiendung:(NSString *)dateiendung
    4. {
    5. self = [super initWithFrame:frame];
    6. if (self) {
    7. self.backgroundColor = [UIColor clearColor];
    8. self.aktiv = FALSE;
    9. //Verzeichniss
    10. ordner = verzeichniss;
    11. //Dateiendung
    12. dateiformat = dateiendung;
    13. //Slideshow
    14. iV_slideshow = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
    15. [self addSubview:iV_slideshow];
    16. }
    17. return self;
    18. }
    19. //Einstellung
    20. -(void)einstellung{
    21. //Anzahl Bilder
    22. anz_bilder = [Bilderimport anz_bilder:ordner];
    23. //Zähler
    24. zaehler = anz_bilder;
    25. }
    26. //Start
    27. -(void)start{
    28. if (iV_slideshow) {
    29. self.aktiv = TRUE;
    30. if (zaehler < anz_bilder) {
    31. zaehler++;
    32. }
    33. else{
    34. zaehler = 1;
    35. }
    36. [UIView transitionWithView:self
    37. duration:3.0
    38. options:UIViewAnimationOptionTransitionCrossDissolve
    39. animations:^{
    40. iV_slideshow.image = [UIImage imageWithContentsOfFile:[Bilderimport bilderzeichniss:ordner Filename:[NSString stringWithFormat:@"%d.%@",zaehler,dateiformat]]];
    41. }
    42. completion:^(BOOL finished){
    43. [NSTimer scheduledTimerWithTimeInterval:3.0
    44. target:self
    45. selector:@selector(start)
    46. userInfo:nil
    47. repeats:NO];
    48. }];
    49. }
    50. }
    51. //Ende
    52. -(void)ende{
    53. self.aktiv = FALSE;
    54. iV_slideshow = nil;
    55. }
    Alles anzeigen


    Hoffe hier ist das Problem zu erkennen!
  • Ich glaube Michael meinte dieses slideshow

    Quellcode

    1. slideshow = [[Slideshow alloc] initWithFrame:CGRectMake(0.0, 20.0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height) setVerzeichniss:@"Grunddaten/startbilder" setDateiendung:@"png"];


    Da es dort nicht deklariert ist, ist es sicher im ViewController deklariert und dort als iVar oder Property? Diese wird natürlich erst freigegeben wenn der ViewController freigegeben wird. Das passier aber nicht by viewDidDisappear, also bleibt die Slideshow auch erhalten.

    Wenn insertSubView() selber eine referenz hält (ich bin gerade niht sicher ab eigentlich ist das ja anzunehmen), dann solltest du slideshow einfach lokal deklarieren und damit wird DEINE REferenz direkt wieder freigegeben und die Refernz vom insertSubView dann beim viewDidDisappear

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    Ich glaube Michael meinte dieses slideshow

    Quellcode

    1. slideshow = [[Slideshow alloc] initWithFrame:CGRectMake(0.0, 20.0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height) setVerzeichniss:@"Grunddaten/startbilder" setDateiendung:@"png"];


    Da es dort nicht deklariert ist, ist es sicher im ViewController deklariert und dort als iVar oder Property? Diese wird natürlich erst freigegeben wenn der ViewController freigegeben wird. Das passier aber nicht by viewDidDisappear, also bleibt die Slideshow auch erhalten.

    Wenn insertSubView() selber eine referenz hält (ich bin gerade niht sicher ab eigentlich ist das ja anzunehmen), dann solltest du slideshow einfach lokal deklarieren und damit wird DEINE REferenz direkt wieder freigegeben und die Refernz vom insertSubView dann beim viewDidDisappear

    Gruß

    Claus


    Danke für die Antwort! :)

    Über iVar:

    Quellcode

    1. @interface Startseite ()
    2. {
    3. Slideshow *slideshow;
    4. }


    Ich verstehe momentan diesen Part nicht:
    "dann solltest du slideshow einfach lokal deklarieren und damit wird DEINE REferenz direkt wieder freigegeben und die Refernz vom insertSubView dann beim viewDidDisappear"

    slideshow deklariere ich doch schon lokal in dem ViewController Startseite oder nicht?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von kruemel1770 ()

  • Wie Michael schon gesagt hat, ist slideshow eine starke Referenz auf den View. Die verhindert das Löschen des Views bis Du oder die Runtime ihr ein neues Objekt (oder nil) zuweist. Dein Problem kannst Du auch über eine schwache Referenz lösen. Allerdings musst Du dann den View bis zum Einfügen über eine starke Referenz halten:

    Quellcode

    1. Slideshow *theSlideshow = [[Slideshow alloc] ...];
    2. [self addSubview:theSlideshow]; // Jetzt hält auch self die Slideshow
    3. slideshow = theSlideshow;
    „Meine Komplikation hatte eine Komplikation.“