Gestion de la mémoire dans iOS / ManagedObjectContext
-
11-10-2019 - |
Question
On dirait que je ne comprenais pas la gestion de la mémoire en Objective C ... soupir.
Je le code suivant (notez que dans mon cas, placemark.thoroughfare
et placemark.subThoroughfare
sont tous deux remplis de données valides, donc les conditions de if
seront-TRUE
item
est liée à un ManagedObjectContext
. Les variables gérées dans item
telles que place
ont setters / getters créés avec @dynamic
. Ainsi, la déclaration est
@property (nonatomic, retain) NSString *place;
@dynamic place;
Plus tard dans le code, dans le ReverseGeocoderDelegate, je y accéder:
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
if (placemark.thoroughfare) {
[item.place release];
item.place = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];
} else {
[item.place release];
item.place = @"Unknown Place";
}
if (placemark.thoroughfare && placemark.subThoroughfare) {
// *** problem is here ***
[item.place release];
item.place = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];
}
Si je ne libère item.place
à l'emplacement marqué dans le code, Instruments trouve une fuite de mémoire là. Si je le fais, le programme se bloque dès que j'essaie d'accéder item.place
en dehors de la méthode incriminée.
Toutes les idées?
La solution
Tout d'abord, je voudrais changer la logique comme ceci:
NSString *newPlace = nil;
if (placemark.thoroughfare && placemark.subThoroughfare) {
newPlace = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];
}
else {
if (placemark.thoroughfare) {
newPlace = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];
}
else {
newPlace = @"Unknown Place";
}
}
item.place = newPlace; // Either nil of valid string can be assigned to
Utilisation de sortie pour re-initialiser le pointeur est tout simplement pas recommandé par beaucoup. Vous ne devez pas le faire si elle était de sauver un peu de mémoire.
Votre logique précédente ne libérant deux fois . Qu'est-ce que la libération n'est d'abord simplement décrémentation retainCount
. Si c'est 0, l'objet est désalloué. Objet ne sera pas désallouée jusqu'à ce que son retainCount
est 0.
En supposant que votre élément a la propriété conserviez et puisque revient stringWithFormat:
chaîne de autoreleased
, donc à la 2ème version, vous essayez de libérer ce qui allait être autoreleased
de toute façon.
La meilleure façon de dégager un plusieurs fois l'objet est simplement attribuer nil
à elle.
Autres conseils
Un point de départ serait de relire sur les propriétés parce que vous n'avez pas besoin de faire `[item.place release] » partout. Ainsi, vous pouvez les supprimer. Le code dynamique créée par le moteur d'exécution pour permettre que la propriété gère automatiquement libérant quoi que ce soit précédemment affecté.
En outre, le [NSString stringWithFormat:...
crée un objet autorelease (ne sais pas si vous saviez que :-) ce qui signifie que si vous où la gestion manuelle de la mémoire pour une variable (non une propriété), alors vous devez retenir / libérer. Mais parce que vous utilisez des propriétés, vous n'avez pas.
Je ne vois pas pourquoi les instruments est de trouver une fuite de mémoire. Peut-être un peu de code est plus à faire. Par exemple, si vous êtes allé item.place = [NSString alloc] initWith...];
alors je pense que vous en avez besoin.
Le crash je soupçonne d'être à cause des rejets à l'origine de conserver compte de zéro et de déclenchement des erreurs d'accès mauvais exec.
L'espoir qui aide.