Frage

ich eine Anwendung, die im Hintergrund läuft nur (durch LSBackgroundOnly in der info.plist Datei angeben). Das Problem ist, dass alle Blöcke, die auf parallelen I Warteschlangen ausgeführt werden, nicht freigegeben werden. Der Code wird in einem Speicher verwalteten Umgebung ausgeführt - Nr. GC beteiligt ist

Die (vereinfacht) Code sieht wie unten. Blubber ist nur einige Dummy-Klasse, die ein NSDate zum Testen hält. Außerdem ist es überschreibt retain, release und dealloc einige Protokollierung zu tun:

NSOperationQueue *concurrentQueue = [[NSOperationQueue alloc] init];
[concurrentQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];

Blubber *aBlubber = [[Blubber alloc] init]; 
aBlubber.aDate = [NSDate date];

[concurrentQueue addOperationWithBlock:^{       
NSAutoreleasePool *blockPool = [[NSAutoreleasePool alloc] init];
    NSDate *test = [aBlubber aDate];
    NSLog(@"Block DONE");
    [blockPool release];    
}];

[aBlubber release];

[concurrentQueue release];

Wenn ich die Anwendung ändern, um eine normale (d.h. nicht-backgound) -Anwendung zu sein, kann ich die Blöcke beobachtet freigegeben werden, wann immer irgendeine Eingabe über die Benutzeroberfläche vorgenommen wird (selbst in ein anderen Fenster den Fokus zu ändern, ist ausreichend). Da mein backgorund App Eingang direkt über den HID-USB-Treiber empfängt und es nicht ein Fenster oder eine Menüleiste hat dies nicht geschieht.

Gibt es eine Möglichkeit, manuell die Runloop zwingen oder was auch immer ist dafür verantwortlich, die Warteschlangen zu sagen, die fertigen Blöcke zu lösen?

(Alle anderen Objekte, die auch durch die Blöcke zurückgehalten worden war, nicht freigegeben, wodurch große Speicherlecks. Diese Lecks können nicht spottet durch die Leaks oder ObjectAllocations Tools sein, aber der Speicherverbrauch kann mit oben beobachtet werden sprunghaft an.)

War es hilfreich?

Lösung

Ein gemeinsames „Gotcha“ für Autorelease-Pools ist, dass, wenn die App-Speicher ohne Empfang Ereignisse aufbaut, die äußerste Pool (die von der Ereignisschleife verwaltet) nicht Trockenlegung werden.

Ich glaube nicht, das sollte hier gelten, da Sie Ihren eigenen Pool sind die Verwaltung ... aber nur für den Fall, könnten Sie versuchen, diese:

...
//When no events are coming in (i.e. the user is away from their computer), the runloop doesn't iterate, and we accumulate autoreleased objects
[[NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:@selector(kickRunLoop:) userInfo:nil repeats:YES] retain];
...
- (void) kickRunLoop:(NSTimer *)dummy
{
// Send a fake event to wake the loop up.
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
                                    location:NSMakePoint(0,0)
                               modifierFlags:0
                                   timestamp:0
                                windowNumber:0
                                     context:NULL
                                     subtype:0
                                       data1:0
                                       data2:0]
         atStart:NO];
}

Andere Tipps

Es sieht aus wie Sie einen Stapel basierten Block verwenden, der verwendet wird, nachdem der Block des Umfangs erloschen ist. Der Block muss kopiert werden. Der Code sollte funktionieren, wenn es so weit geändert wird:

[concurrentQueue addOperationWithBlock:[[^{       
    NSAutoreleasePool *blockPool = [[NSAutoreleasePool alloc] init];
    NSDate *test = [aBlubber aDate];
    NSLog(@"Block DONE");
    [blockPool release];    
}copy]autorelease]];

Werfen Sie einen Blick auf diesen Beitrag für eine volle Zuschreibung auf Blöcke: http://gkoreman.com/blog/2011/02/27/blocks-in-c-and-objective-c/

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top