Wie kann ich Objekte freigegeben werden, wenn Sie mit Objective-C ARC mit Xcode 4.2?
ETA: Siehe unten für mehr info, die ich bekam durch die Erstellung von Profilen der app.
Habe ich eine iPhone-app, die ich gerade umgebaut zu verwenden, ARC, und jetzt bin ich immer mehrere Fehler, weil der zombie-Objekte. Bevor ich wechselte, ich wurde manuell behalten Sie, und alles war in Ordnung. Ich kann nicht herausfinden, warum der BOGEN nicht behalten Sie. Die Objekte deklariert sind, als die starken Eigenschaften, und verwiesen mit dot-notation. Dies geschieht an mehreren stellen, so dass ich denke, ich muss ein grundlegendes Missverständnis von ARC/memory-management-irgendwo.
Hier ist ein Beispiel, das besonders frustrierend. Ich habe ein NSMutableArray von 3 Objekten. Jedes dieser Objekte hat eine Eigenschaft, die auch ein NSMutableArray, die in diesem Fall immer ein einzelnes Objekt. Endlich, das Objekt, hat die Eigenschaft, dass veröffentlicht wird. Der Grund, warum es frustrierend ist, dass es nur passiert mit dem 3. Objekt aus dem ursprünglichen array. Die ersten 2 Objekte sind immer völlig in Ordnung. Es macht einfach keinen Sinn für mich, wie die Eigenschaft eines Objekts freigegeben werden, wenn die gleiche Eigenschaft der ähnliche Objekte erstellt und verwendet in der gleichen Weise nicht.
Dem array gespeichert ist, als eine Eigenschaft, die auf einem UITableViewController:
@interface GenSchedController : UITableViewController <SectionHeaderViewDelegate>
@property (nonatomic, strong) NSArray *classes;
@end
@implementation GenSchedController
@synthesize classes;
Den Objekten, die gespeichert sind in der classes
array sind wie folgt definiert:
@interface SchoolClass : NSObject <NSCopying, NSCoding>
@property (nonatomic, strong) NSMutableArray *schedules;
@end
@implementation SchoolClass
@synthesize schedules;
Den Objekten, die gespeichert sind in der schedules
array sind wie folgt definiert:
@interface Schedule : NSObject <NSCopying, NSCoding>
@property (nonatomic, strong) NSMutableArray *daysOfWeek;
@implementation Schedule
@synthesize daysOfWeek;
daysOfWeek
ist, was man immer freigegeben. Es enthält mehrere NSStrings.
Kann ich sehen, dass während viewDidLoad
alle Gegenstände sind fein, keine zombies. Allerdings, wenn ich Tippen Sie auf eine der Zellen der Tabelle, und legen Sie einen Haltepunkt auf die erste Zeile der tableView:didSelectRowAtIndexPath:
es wurde bereits veröffentlicht. Die spezielle Zeile, die den Fehler auslöst ist die @synthesize daysOfWeek;
, die aufgerufen wird, nachdem der 3. "for" - Schleife unten:
for (SchoolClass *currentClass in self.classes) {
for (Schedule *currentSched in currentClass.schedules) {
for (NSString *day in currentSched.daysOfWeek)
Aber nochmal, das passiert nur auf die Letzte Liste des letzten SchoolClass.
Kann jemand mich in die richtige Richtung in meiner app, um korrekt zu arbeiten mit ARC?
Wie gewünscht, hier weitere Infos. Zuerst der stack-trace, wenn die Ausnahme ausgelöst wird:
#0 0x01356657 in ___forwarding___ ()
#1 0x01356522 in __forwarding_prep_0___ ()
#2 0x00002613 in __arclite_objc_retainAutoreleaseReturnValue (obj=0x4e28b80) at /SourceCache/arclite_host/arclite-4/source/arclite.m:231
#3 0x0000d2fc in -[Schedule daysOfWeek] (self=0x4e28680, _cmd=0x220d6) at /Users/Jesse/Documents/Xcode/Class Test/Schedule.m:18
#4 0x0001c161 in -[SchedulesViewController doesScheduleOverlap:schedule2:withBufferMinutes:] (self=0x692b210, _cmd=0x22d58, schedule1=0x4e28680, schedule2=0x4e27f10, buffer=15) at /Users/Jesse/Documents/Xcode/Class Test/Classes/SchedulesViewController.m:27
#5 0x0001c776 in -[SchedulesViewController doesScheduleOverlap:schedule2:] (self=0x692b210, _cmd=0x22d9b, schedule1=0x4e28680, schedule2=0x4e27f10) at /Users/Jesse/Documents/Xcode/Class Test/Classes/SchedulesViewController.m:53
#6 0x0001cf8c in -[SchedulesViewController getAllowedSchedules] (self=0x692b210, _cmd=0x22dca) at /Users/Jesse/Documents/Xcode/Class Test/Classes/SchedulesViewController.m:78
#7 0x0001d764 in -[SchedulesViewController viewDidLoad] (self=0x692b210, _cmd=0x97cfd0) at /Users/Jesse/Documents/Xcode/Class Test/Classes/SchedulesViewController.m:121
#8 0x00620089 in -[UIViewController view] ()
#9 0x0061e482 in -[UIViewController contentScrollView] ()
#10 0x0062ef25 in -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] ()
#11 0x0062d555 in -[UINavigationController _layoutViewController:] ()
#12 0x0062e7aa in -[UINavigationController _startTransition:fromViewController:toViewController:] ()
#13 0x0062932a in -[UINavigationController _startDeferredTransitionIfNeeded] ()
#14 0x00630562 in -[UINavigationController pushViewController:transition:forceImmediate:] ()
#15 0x006291c4 in -[UINavigationController pushViewController:animated:] ()
#16 0x000115d5 in -[GenSchedController tableView:didSelectRowAtIndexPath:] (self=0x4c57b00, _cmd=0x9ac1b0, tableView=0x511c800, indexPath=0x4e2cb40) at /Users/Jesse/Documents/Xcode/Class Test/Classes/GenSchedController.m:234
#17 0x005e7b68 in -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] ()
#18 0x005ddb05 in -[UITableView _userSelectRowAtPendingSelectionIndexPath:] ()
#19 0x002ef79e in __NSFireDelayedPerform ()
#20 0x013c68c3 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#21 0x013c7e74 in __CFRunLoopDoTimer ()
#22 0x013242c9 in __CFRunLoopRun ()
#23 0x01323840 in CFRunLoopRunSpecific ()
#24 0x01323761 in CFRunLoopRunInMode ()
#25 0x01aa71c4 in GSEventRunModal ()
#26 0x01aa7289 in GSEventRun ()
#27 0x0057ec93 in UIApplicationMain ()
#28 0x0000278d in main (argc=1, argv=0xbffff5fc) at /Users/Jesse/Documents/Xcode/Class Test/main.m:16
Und die genaue Ausnahme ist Class Test[82054:b903] *** -[__NSArrayM respondsToSelector:]: message sent to deallocated instance 0x4e28b80
Und hier der code wo alles angelegt wird, das laden von der Festplatte:
NSString *documentsDirectory = [FileManager getPrivateDocsDir];
NSError *error;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:&error];
//Create SchoolClass for each file
NSMutableArray *classesTemp = [NSMutableArray arrayWithCapacity:files.count];
for (NSString *file in files) {
if ([file.pathExtension compare:@"sched" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:file];
NSData *codedData = [[NSData alloc] initWithContentsOfFile:fullPath];
if (codedData == nil) break;
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData];
SchoolClass *class = [unarchiver decodeObjectForKey:@"class"];
[unarchiver finishDecoding];
class.filePath = fullPath;
[classesTemp addObject:class];
}
}
self.classes = classesTemp;
Den initWithCoder: Methoden sind wirklich einfach. Zunächst für SchoolClass:
- (id)initWithCoder:(NSCoder *)decoder {
self.name = [decoder decodeObjectForKey:@"name"];
self.description = [decoder decodeObjectForKey:@"description"];
self.schedules = [decoder decodeObjectForKey:@"schedules"];
return self;
}
Und zum Zeitplan:
- (id)initWithCoder:(NSCoder *)decoder {
self.classID = [decoder decodeObjectForKey:@"id"];
self.startTime = [decoder decodeObjectForKey:@"startTime"];
self.endTime = [decoder decodeObjectForKey:@"endTime"];
self.daysOfWeek = [decoder decodeObjectForKey:@"daysOfWeek"];
return self;
}
Ich habe versucht mit einem Profil auf der app mit den Zombies Vorlage und den Vergleich von Objekt, das über-releases zu einem der anderen in dem array, das ist in Ordnung. Ich kann sehen, dass auf der Linie for (NSString *day in currentSched.daysOfWeek)
, dass es geht in die daysOfWeek getter, die nicht retain autorelease
. Dann, nachdem er wieder aus dem getter ist, tut es ein anderer retain
(Vermutlich halten das Eigentum, während die Schleife abgearbeitet ist, und dann eine release
. Alle, die für das problem-Objekt als für die gesunde Objekt. Der Unterschied ist, dass sofort nach, dass release
das problem-Objekt ruft release
WIEDER. Dies ist eigentlich nicht dazu führen, dass ein problem sofort, weil der autorelease-pool nicht abgelassen noch, aber sobald es tut, werden die retain-count sinkt auf 0, und dann natürlich das nächste mal werde ich versuchen, darauf zuzugreifen, es ist ein zombie.
Was ich kann nicht herausfinden, der Grund, WARUM das extra release
immer es genannt. Aufgrund der äußeren for-Schleifen, die Anzahl der Zeiten, die currentSched.daysOfWeek
aufgerufen wird variieren - es wird als 3-mal auf das problem-Objekt und 5 auf der gesunden Objekt, aber die extra release
tritt das erste mal ist es aufgerufen, so bin ich nicht sicher, wie Sie Sie beeinflussen würden.
Tut dies extra info jemand helfen zu verstehen, was geschieht?
@synthesize
innerhalb der for-Schleife? Und wie sind Sie mit der Bestimmung, dass es veröffentlicht wurde, wenn keine zombies erscheinen?konnte Sie nach dem code, wo Sie erstellen, die diese Objekt?
Ich denke, die
@systhesize
wird gesprungen, um in den debugger, wenn er ruft den accessor currentSched.daysOfWeek
in der for-Schleife.Hast du zufällig import YourClass.m eher als YourClass.h irgendwo? Irgendeinem Grund ich glaube, ich habe etwas gesehen, wie dies vor, wenn ich versehentlich getan habe. Sollten Sie nicht haben, um wirklich zu verstehen Speicherverwaltung bei der Verwendung von ARC. Ich vermute, etwas ist falsch konfiguriert.
Können Sie den stack-trace. Und ist es non-ARC code in der app?
InformationsquelleAutor Elezar | 2011-12-06
Du musst angemeldet sein, um einen Kommentar abzugeben.
ARC ist alles über das Objekt Eigentum. Sie haben eine starke Zeiger auf das Objekt, das Sie referenzieren? Wenn dem so ist, wird das Objekt beibehalten.
Wenn ich umgewandelt mein Projekt auf ARC bekam ich einen
message sent to deallocated instance
Fehler als auch ein Fehler, dass die nicht zeigen, bis in meine pre-ARC code. Die Erklärung war diese: in meinem pre-ARC-code, den ich hatte ein memory-leak. Ich behielt ein Objekt und dann nie veröffentlicht. Ich war später Referenzierung von einer schwachen Zeiger (Delegierter Zeiger). Wenn ich wechselte zu ARC, das Speicher-management wurde aufgeräumt und so, sobald ich nicht mehr hatte einen starken Zeiger auf das Objekt, das es veröffentlicht wurde. Also, wenn ich den Zugriff versucht es mit dem unsafe-Zeiger, es ist abgestürzt.Folgen Sie einfach den Besitz und die Objekt-Graphen zeichnen - dies wird Ihnen helfen zu verfolgen, den Fehler zu finden.
InformationsquelleAutor bearMountain
So, ich habe herausgefunden, wie, um dies zu halten, obwohl ich bin immer noch verwirrt darüber, warum es einen Unterschied macht. In jedem Ort, wo die zusätzliche Veröffentlichung geschehen war, es war in einer Schleife. In jenen Orten, ich nahm die Deklaration einer Eigenschaft aus der for-Schleife zugewiesen, um eine lokale var, die in der for-Schleife, und es funktioniert gut jetzt! Also, eine Linie, dass verwendet werden:
Habe ich geändert 2 Zeilen:
Natürlich, das wird einen Unterschied machen in der retain/release-Aufrufe, die benötigt werden, aber ich sehe nicht ein, warum es letztendlich einen Unterschied macht, in der letzten retain count... Wenn jemand erhellen können einen Einblick darüber, warum dies hilft, würde ich es gerne hören!
schedule1.daysOfWeek
veröffentlicht wurde, während die Schleife—zum Beispiel, wenn SiedaysOfWeek
innerhalb der Schleife. Die zweite version weist daysOfWeek zu einem stark variabel, so ist es am Leben gehalten, bis die Schleife beendet; die erste version nicht, so dass die array ' s Leben, ist die Laune vonschedule1
.InformationsquelleAutor Elezar