Mémoire non libérée pour MKMapView avec ARC

J'ai un UIView personnalisé appelé ActivityDetailView que UIView et que j'ajoute à une scrollview dans un controller de vue parent. Lorsque cette vue personnalisée est allouée, elle prend environ 1 Mo à chaque fois de memory supplémentaire et Instruments montre que la memory n'est jamais libérée même si la vue et le controller de vue parents ont chacun leur méthode dealloc appelée. Je reçois des avertissements de memory et l'application est en train de se faire tuer, donc je suis évidemment en train de faire quelque chose de mal.

Mise à jour w / info sur la vue de la carte étant la cause, mais j'ai besoin d'une solution

Dans le file nib ActivityDetailView personnalisé, une vue de carte est agrandie et cinput autour de l'location des users. Lorsque j'ai supprimé cette vue de carte de la plume pour qu'elle ne dessine pas à l'écran, les problèmes d'allocation de memory ont disparu. Cependant, j'ai évidemment besoin de la vue de la carte. Pourquoi datatables de la vue cartographique ne sont-elles pas diffusées lorsque la vue de carte est hors de scope?

Il y a seulement 1 ActivityDetailView et 1 ActivityDetailViewController vie lorsque la vue est affichée. Dès que j'ouvre la vue de la stack, ils ne vivent plus. N'a pas de sens comment la memory ne cesse de croître même si les objects sont en train d'être tués comme indiqué via Instruments. Si les vues parent sont désallouées, pourquoi datatables de la vue cartographique ne sont-elles pas désallouées?

Qu'est-ce que je fais mal ou que dois-je vérifier?

Voici la vue personnalisée:

 @interface ActivityDetailView () { CLLocation *location; __weak id parentViewController; int scrollViewX; ImageUtility *imageUtility; } @end @implementation ActivityDetailView -(id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { NSArray *xibViews = [[NSBundle mainBundle] loadNibNamed:@"ActivityDetailView" owner:nil options:nil]; if ([xibViews count] < 1) return nil; ActivityDetailView * xibView = [xibViews objectAtIndex:0]; [xibView setFrame:frame]; self = xibView; } return self; } - (id)initWithLocation:(CLLocation *)loc parentController:(id)parent { self = [self initWithFrame:CGRectMake(0, 0, 320, 1000)]; if (self) { imageUtility = [ImageUtility sharedManager]; location = loc; parentViewController = parent; scrollViewX = 0; [self centerMapForActivityLocation]; [self addPhotoButtonWithImageNamed:@"addActivityPhoto.png" target:parentViewController selector:@selector(addPhotoToActivity:)]; } return self; } - (void)dealloc { NSLog(@"ActivityDetailView was dealloced"); } 

Dans le controller de vue parent:

 @interface ActivityDetailViewController () { ActivityDetailView *detailView; } @end @implementation ActivityDetailViewController - (void)viewDidLoad { [super viewDidLoad]; // Some code left out for clarity [self setupView]; } - (void)didReceiveMemoryWarning { NSLog(@"Purging image cache"); [[ImageUtility sharedManager] purgeCache]; } - (void)dealloc { // These essentially do nothing to help the problem detailView.mapView = nil; [detailView removeFromSuperview]; detailView = nil; self.scrollView = nil; NSLog(@"ActivityDetailViewController was dealloced"); } - (void)setupView { // Add the activity detail view to the scroll view detailView = [[ActivityDetailView alloc] initWithLocation:self.activityLocation parentController:self]; [self.scrollView addSubview:detailView]; self.scrollView.contentSize = detailView.frame.size; // Setup the map view detailView.mapView.delegate = self; MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init]; annotation.coordinate = self.activityLocation.coordinate; [detailView.mapView addAnnotation:annotation]; if (self.activity.mapImageName) { detailView.mapView.scrollEnabled = YES; detailView.mapView.zoomEnabled = YES; } else { detailView.mapView.scrollEnabled = NO; detailView.mapView.zoomEnabled = NO; } // Add the weather area to the view dayView = [[DailyButtonView alloc] initWithFrame:CGRectMake(0, -17, 60, 70)]; dayView.hidden = YES; [detailView.weatherView addSubview:dayView]; } 

Voici une image d'Instruments montrant que la majorité de la memory provient du chargement de la plume

Captures d'écran

Je n'ai rien à cacher pour le moment. La vue est essentiellement un scrollview avec une vue de carte à l'intérieur de celui-ci et quelques labels et quelques vues de la table. Les vues de table ne sont pas remplies avec quoi que ce soit et je ne charge aucune image dans la vue autre que l'image d'arrière-plan pour le scrollview, mais cela devrait être libéré quand la vue le fait.

En fait, il y a un bug connu avec iOS 6 et MKMapView ne libérant pas sa memory correctement. Malheureusement, il n'y a pas d'autre solution que d'essayer de forcer la vue de la carte à purger son cache, ce qui n'a pas tellement d'impact sur la libération de la memory.

La chose étrange est que même lorsque l'application reçoit des avertissements de la memory, le cache de la vue de la carte n'est toujours pas purgé correctement. Finalement, l'application devient instable et est tué par le operating system.

Apple a été très bâkeye avec leurs tests ces derniers time. C'est le deuxième bug avec MKMapView que j'ai rencontré (l'autre étant mapViewDidFinishLoadingMap: être appelé au début) et les deux bugs ont été vraiment évidents à attraper s'ils venaient de faire des tests de performances et de santé mentale.

Voici un code qui peut aider:

 - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; // This is for a bug in MKMapView for iOS6 [self purgeMapMemory]; } // This is for a bug in MKMapView for iOS6 // Try to purge some of the memory being allocated by the map - (void)purgeMapMemory { // Switching map types causes cache purging, so switch to a different map type detailView.mapView.mapType = MKMapTypeStandard; [detailView.mapView removeFromSuperview]; detailView.mapView = nil; } 

L'autre chose que vous pourriez faire est d'utiliser une instance de MKMapView dans toute votre application et cela devrait aider à minimiser la quantité de memory allouée chaque fois que la vue est affichée puisque la vue de la carte sera déjà allouée.

Ce n'est pas vraiment la meilleure façon de créer une vue personnalisée à partir de votre file nib. Ce que je vous suggère de faire est d'append la vue que vous prenez du file .nib comme sous-vue à soi-même. Le code devrait ressembler à ceci.

 -(id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { NSArray *xibViews = [[NSBundle mainBundle] loadNibNamed:@"ActivityDetailView" owner:nil options:nil]; if ([xibViews count] < 1) return nil; ActivityDetailView * xibView = [xibViews objectAtIndex:0]; [xibView setFrame:frame]; [self addSubview:xibView]; // This is where I have changed your code } return self; } 

Vous êtes probablement confronté à un problème de cache.

Si vous utilisez beaucoup d'images, une bonne option est de supprimer ces images du file xib et de les append en utilisant du code. Ou si vous chargez les images en utilisant [UIImage imageNamed:@""]

Mais utilisez quelque chose comme ça:

 NSData* dataImg = [NSData dataWithContentsOfFile:@"yourfile.png"]; UIImage* img = [UIImage imageWithData:dataImg]; 

Pour mieux aider j'ai besoin de savoir comment vous démarrez vos tables et aussi les autres fonctionnalités.