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?

Warten Sie, haben Sie @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

Schreibe einen Kommentar