web-dev-qa-db-fra.com

Dois-je quand même copier/Block_copy les blocs sous ARC?

Je viens de tomber sur le sujet SO suivant: Pourquoi devrions-nous copier des blocs plutôt que de les conserver? qui a la phrase suivante:

Cependant, à partir de iOS 6, ils sont traités comme des objets normaux, vous n'avez donc pas à vous inquiéter.

Cette affirmation m'a vraiment troublé. C'est pourquoi je pose la question suivante: cette affirmation implique-t-elle vraiment que les développeurs d'Objective-C n'ont pas besoin de

@property (copy) blockProperties ou

[^(...){...) {} copy]

copier des blocs et leur contenu de pile en tas plus?

J'espère que la description que j'ai faite est claire.

S'il vous plaît, soyez prolixe.


Questions similaires

Sous ARC, les blocs sont-ils automatiquement copiés lorsqu'ils sont affectés directement à un ivar? .

20

ARC copiera le bloc automatiquement. De clang's Comptage automatique de références Objective-C documentation:

À l'exception des retenues effectuées lors de l'initialisation d'une variable de paramètre __strong ou de la lecture d'une variable __weak, chaque fois que ces sémantiques appellent à conserver une valeur de type pointeur de bloc, cela a l'effet d'un Block_copy. L'optimiseur peut supprimer ces copies lorsqu'il constate que le résultat est utilisé uniquement en tant qu'argument d'un appel.

Ainsi, les blocs utilisés uniquement comme arguments de fonction ou d'appels de méthode peuvent rester des blocs de pile, mais dans le cas contraire, ARC conserve le bloc et le copie. Ceci est implémenté par le compilateur émettant un appel à objc_retainBlock(), la implementation qui est:

id objc_retainBlock(id x) {
    return (id)_Block_copy(x);
}

C'est toujours une bonne idée de déclarer les propriétés de bloc comme ayant une sémantique de copie car un bloc assigné à une propriété forte sera en fait copié. Apple recommande ceci aussi:

Vous devez spécifier copy en tant qu'attribut de propriété, car un bloc doit être copié pour garder trace de son état capturé en dehors de l'étendue d'origine. Ce n’est pas un sujet de préoccupation pour vous lorsque vous utilisez le comptage automatique des références, car cela se fera automatiquement, mais il est recommandé que l’attribut property affiche le comportement résultant.

Notez que puisque cette fonctionnalité de copie avec conservation est fournie par ARC, elle dépend uniquement de la disponibilité d'ARC ou d'ARCLite et ne nécessite par ailleurs pas de version de système d'exploitation ni de OS_OBJECT_USE_OBJC particuliers.

35
Matt Stevens

Ma réponse originale était fausse. La réponse modifiée n’est pas une réponse, mais plutôt une question "c’est vraiment une bonne question".

S'il vous plaît, voir la réponse de Matt pour de vraies références, pourquoi les choses sont ce qu'elles sont.

Après avoir testé le code suivant sur iOS7:

int stackVar;
void (^someBlock)() = ^(){};
NSLog(@"int: %x\nblock: %x,\ncopied: %x", (unsigned int)&stackVar, (unsigned int)someBlock, (unsigned int)[someBlock copy]);

J'ai eu ceci:

int: bfffda70
block: 9d9948
copied: 9d9948

Ce qui signifie que les blocs créés et affectés dans des variables de pile sont en fait déjà sur un tas et que leur copie n’a aucune incidence.

Ceci, cependant, n’est sauvegardé par aucune source officielle, car elles indiquent toujours que les blocs créés sur pile doivent être copiés "lors de la transmission".


Une partie de la réponse avant que je teste, indiquant quels documents sont contredits par l'exemple.

Document sur la transition vers l'ARC États:

Les blocs «ne fonctionnent que lorsque vous passez» bloque la pile en mode ARC, comme dans un retour. Vous n’êtes plus obligé d’appeler Block_copy. Vous devez toujours utiliser [^{} copy] lorsque vous transmettez “en bas” la pile à arrayWithObjects: et à d’autres méthodes qui effectuent une retenue.

Et docs sur les blocs et propriétés dit:

Vous devez spécifier copy en tant qu'attribut de propriété, car un bloc doit être copié pour garder trace de son état capturé en dehors de l'étendue d'origine.

1
coverback