Ho cercato di capire il motivo di questo arresto per capire meglio come si comportano i blocchi. Ho una classe davvero semplice per innescare questo crash.Blocco con dispatch_block
@implementation BlockCrashTest
- (void)doSomething
{
dispatch_queue_t queue = dispatch_queue_create("com.queue.test", DISPATCH_QUEUE_SERIAL);
__weak typeof(self) weakSelf = self;
dispatch_block_t block = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
dispatch_group_t group = dispatch_group_create();
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC);
dispatch_group_enter(group);
[strongSelf performSomethingAsync:^{
dispatch_group_leave(group);
}];
if(dispatch_group_wait(group, time) != 0) {
NSLog(@"group already finished");
}
};
dispatch_async(queue, block);
}
- (void)performSomethingAsync:(void(^)(void))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(5);
completion();
});
}
- (void)dealloc
{
NSLog(@"released object");
}
@end
Ora, se io allocare la classe e semplicemente il metodo chiamano doSomething ad esso,
BlockCrashTest *someObject = [[BlockCrashTest alloc] init];
[someObject doSomething];
Si blocca con l'eccezione, EXC_BAD_INSTRUCTION e seguente stack tracce,
#0 0x000000011201119a in _dispatch_semaphore_dispose()
#1 0x0000000112013076 in _dispatch_dispose()
#2 0x0000000112026172 in -[OS_dispatch_object _xref_dispose]()
#3 0x000000010ef4c2fd in __29-[BlockCrashTest doSomething]_block_invoke at /Users/Sandeep/Desktop/Test Block Crash/Test Block Crash/ViewController.m:35
#4 0x0000000112005ef9 in _dispatch_call_block_and_release()
Se modifico il metodo doSomething, tale da non utilizzare debole ma utilizza sé poi l'incidente non si verificano e metodi sembrano eseguire come previsto,
- (void)doSomething
{
dispatch_queue_t queue = dispatch_queue_create("com.queue.test", DISPATCH_QUEUE_SERIAL);
dispatch_block_t block = ^{
dispatch_group_t group = dispatch_group_create();
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC);
dispatch_group_enter(group);
[self performSomethingAsync:^{
dispatch_group_leave(group);
}];
if(dispatch_group_wait(group, time) != 0) {
NSLog(@"group already finished");
}
};
dispatch_async(queue, block);
}
Perché si pianta, la mia comprensione è che l'utilizzo di deboli all'interno del blocco farei in modo che il metodo non venga chiamato, se l'oggetto viene rilasciato e ho pensato che debole sia più sicuro dell'utilizzo di self all'interno del blocco.
Il codice precedente funziona bene con weakSelf, se mantengo l'oggetto BlockCrashTest e chiamare il metodo ad esso.
Sarei davvero felice se qualcuno potesse spiegare il motivo dello schianto e cosa succederà esattamente con queste 3 diverse varianti di codice sopra che un crash e altri sembrano funzionare correttamente.
Nota: Questo è, in un modo o l'altro relativo al crollo elencati in filo, Objective-C crash on __destroy_helper_block_. Sono stato in grado di riprodurre le stesse identiche tracce dello stack con il mio codice sopra.
Potete anche darmi un indizio sul motivo per cui non si blocca, se uso self all'interno del blocco? È solo perché il blocco conserva se stesso? – Sandeep
@GeneratorOfOne - Poiché la presenza di 'self' stabilisce un riferimento forte all'interno del blocco, che non viene risolto fino all'esecuzione del blocco. Quindi 'weakSelf' non è' nil' e 'strongSelf' non è' nil' neanche. Così, il blocco del gestore di completamento in 'performSomethingAsync' viene chiamato, assicurando che" enter "sia ora bilanciato da un" leave ". Ma se volevi che il blocco conservasse l'oggetto, ovviamente non avresti attraversato la danza Debole/forte. – Rob
Questa è una buona spiegazione. Quindi, posso avere qualche oggetto autorelued che può ancora fare qualche lunga chiamata asincrona e rimanere in giro se usassi me stesso, invece di usare debole/forte. Mentre se l'oggetto è se mantenuto da solo, allora ha senso avere debole/forte, è quel senso di questa cosa? – Sandeep