/ / Blocchi di cacao come indicatori forti rispetto alla copia: obiettivo-c, cacao, conteggio automatico-rif, blocchi-obiettivo

Il cacao blocca come punti forti contro copia - obiettivo-c, cacao, conteggio automatico dei ref-in, blocchi obiettivo-c

Ho lavorato più volte con i blocchi come con i puntatori a cui avevo un forte riferimento

Ho sentito che dovresti usare la copia, ma qual è l'implicazione nel lavorare con i blocchi come puntatori e non con l'oggetto grezzo?

Non ho mai ricevuto un reclamo dal compilatore, che non dovrei usare

@property (nonatomic, strong) MyBlock block;

ma dovrebbe usare

@property (nonatomic, copy) MyBlock block;

per quanto ne so, il blocco è solo un oggetto, quindi perché preferire la copia comunque?

risposte:

40 per risposta № 1

Risposta breve

La risposta è che è storica, hai completamente ragione sul fatto che nel codice ARC corrente non è necessario utilizzare copy e a strong la proprietà va bene. Lo stesso vale per le variabili locali e globali.

Risposta lunga

A differenza di altri oggetti un blocco potrebbe essere immagazzinato nello stack, questo è un file ottimizzazione dell'implementazione e come tale dovrebbe, come altri compilatoriottimizzazioni, non hanno un impatto diretto sul codice scritto. Questa ottimizzazione avvantaggia un caso comune in cui un blocco viene creato, passato come argomento di metodo / funzione, utilizzato da quella funzione e quindi scartato: il blocco può essere rapidamente allocato sullo stack e quindi eliminato senza l'heap (pool di memoria dinamica) essere coinvolti.

Confronta questo a variabili locali, che (a) ha creato su pila, (b) vengono automaticamente distrutti al momento del possessoritorni di funzioni / metodi e (c) possono essere passati per indirizzo a metodi / funzioni chiamati dalla funzione proprietaria. L'indirizzo di una variabile locale non può essere memorizzato e utilizzato dopo la sua funzione / metodo proprietario ha return - la variabile non esiste più.

però oggetti dovrebbero sopravvivere alla loro funzione / metodo di creazione (se richiesto), quindi a differenza delle variabili locali sono allocate nel file mucchio e non vengono automaticamente distrutti in base alla loro creazione di funzione / metodo restituito, ma piuttosto in base al fatto che siano ancora necessari - e il "bisogno" qui è determinato automaticamente da ARC in questi giorni.

La creazione di un blocco sullo stack può ottimizzare acaso comune, ma causa anche un problema: se il blocco deve sopravvivere al suo creatore, come spesso fanno gli oggetti, deve essere spostato nell'heap prima che lo stack del suo creatore venga distrutto.

Quando l'implementazione del blocco è stata rilasciata per la prima voltal'ottimizzazione della memorizzazione dei blocchi nello stack è stata resa visibile ai programmatori poiché il compilatore in quel momento non era in grado di gestire automaticamente lo spostamento del blocco nell'heap quando necessario - i programmatori dovevano usare una funzione block_copy() per farlo da soli.

Anche se questo approccio potrebbe non essere fuori luogo inil mondo C di basso livello (ei blocchi sono costrutti C), avere programmatori Objective-C di alto livello che gestiscono manualmente un'ottimizzazione del compilatore non è davvero buono. Quando Apple ha rilasciato versioni più recenti del compilatore, sono stati apportati miglioramenti. All'inizio, ai programmatori fu detto che potevano sostituire block_copy(block) con [block copy], adattandosi ai normali oggetti Objective-C. Quindi il compilatore ha iniziato a copiare automaticamente i blocchi dallo stack secondo necessità, ma questo non è stato sempre documentato ufficialmente.

Non è stato necessario copiare manualmente i blocchifuori dallo stack per un po ', anche se Apple non riesce a scrollarsi di dosso le sue origini e si riferisce a farlo come "best practice", il che è certamente discutibile. Nell'ultima versione, settembre 2014, di Apple "s Lavorare con i blocchi, hanno affermato che le proprietà con valori di blocco dovrebbero utilizzare copy, ma poi torna subito pulito (enfasi aggiunto):

Nota: È necessario specificare copy come attributo della proprietà, poiché un blocco deve essere copiato per tenere traccia del suo stato acquisito al di fuori dell'ambito originale. Questo non è qualcosa di cui ti devi preoccupare quando utilizzi il conteggio automatico dei riferimenti, poiché avverrà automaticamente, ma è consigliabile che l'attributo di proprietà mostri il comportamento risultante.

Non è necessario "mostrare il comportamento risultante": memorizzare il blocco nello stack in primo luogo è un file ottimizzazione e dovrebbe essere trasparente al codice - proprio come le altre ottimizzazioni del compilatore, il codice dovrebbe ottenere il vantaggio in termini di prestazioni senza il coinvolgimento del programmatore.

Finché usi ARC e l'attuale Clangcompilatori puoi trattare i blocchi come altri oggetti e poiché i blocchi sono immutabili significa che non devi copiarli. Fidati di Apple, anche se sembrano avere nostalgia dei "bei vecchi tempi in cui facevamo le cose a mano" e incoraggia di lasciare promemoria storici nel codice, copy non è necessario

La tua intuizione era giusta.

HTH


3 per risposta № 2

Stai chiedendo informazioni sul modificatore di proprietà per una proprietà. Ciò influisce sul getter e / o setter sintetizzato (o auto-sintetizzato) per la proprietà se è sintetizzato (o auto-sintetizzato).

La risposta a questa domanda sarà diversa tra MRC e ARC.

  • In MRC, i modificatori della proprietà della proprietà includono assign, retain, e copy. strong è stato introdotto con ARC e quando strong è utilizzato in MRC, è sinonimo di retain. Quindi la domanda sarebbe sulla differenza tra retain e copy, e c'è molta differenza, perché copy"s setter salva una copia del valore dato.

    I blocchi devono essere copiati per essere utilizzati all'esterno diambito in cui è stato creato (con un blocco letterale). Poiché la tua proprietà memorizzerà il valore come variabile di istanza che persiste tra le chiamate di funzione, ed è possibile che qualcuno assegni un blocco non occupato dall'ambito in cui è stato creato, la convenzione è che devi copiarlo. copy è il giusto modificatore di proprietà.

  • In ARC, strong rende la variabile di istanza sottostante __strong, e copy lo fa anche __strong e aggiunge la semantica di copia al setter. Tuttavia, ARC garantisce anche che ogni volta che un valore viene salvato in un file __strong variabile di tipo puntatore a blocchi, viene eseguita una copia. La tua proprietà ha un tipo MyBlock, che presumo sia un typedef per un tipo di puntatore a blocchi. Pertanto, se il qualificatore di proprietà lo fosse, verrà comunque eseguita una copia nel setter strong. Quindi, in ARC, non c'è differenza tra l'utilizzo di strong e copy per questa proprietà.

Se questa dichiarazione potrebbe essere utilizzata sia in MRC che in ARC (ad esempio un'intestazione in una libreria), sarebbe una buona idea usare copy in modo che funzioni correttamente in entrambi i casi.


2 per risposta № 3
what is the implication in working with blocks as pointers and not with the raw object?

Non stai mai usando il valore grezzo, hai sempre un puntatore a un blocco: un blocco è un oggetto.

Guardando il tuo esempio specifico, presumo che tu voglia mantenere il blocco in giro, "quindi perché preferire la copia comunque"enter code here? Beh, è ​​una questione di sicurezza (questo esempio è tratto dal blog di Mike Ash). Poiché i blocchi sono allocati sullo stack (e non sull'heap come il resto degli oggetti in Objective-c), quando fai qualcosa del genere:

[dictionary setObject: ^{ printf("hey heyn"); } forKey: key];

Stai allocando il blocco sullo stack framedell'ambito corrente, quindi quando l'ambito termina (ad esempio, restituendo il dizionario), lo stack frame viene distrutto e il blocco va con esso. Quindi ti sei procurato un puntatore penzolante. Consiglierei di leggere L'articolo di Mike completamente. Ad ogni modo, puoi andare con un file strong proprietà se quando si assegna il blocco lo si copia:

self.block = [^{} copy];

Modificare: Dopo aver esaminato la data dell'articolo di Mike, presumo che questo fosse il comportamento Pre-ARC. Su ARC sembra che funzioni come previsto e non si blocca.

Edit2: Dopo aver sperimentato con Non-ARC, non si blocca neanche. Ma questo esempio mostra risultati diversi a seconda dell'uso o meno di ARC:

void (^block[10])();

int i = -1;
while(++i < 10)
block[i] = ^{ printf("%dn", i); };


for(i = 0; i < 10; i++)
block[i]();

Citando Mike Ashe sui diversi risultati:

Il motivo per cui stampa dieci 9 nel primo casoè abbastanza semplice: il il blocco che viene creato all'interno del ciclo ha una durata che è legata a ambito interno del ciclo. Il blocco viene distrutto alla successiva iterazione di il ciclo e quando si lascia il ciclo. Ovviamente "distruggere" significa solo che il suo slot nello stack sia disponibile per essere sovrascritto. E 'solo accade che il compilatore riutilizzi lo stesso slot ogni volta attraverso il file loop, quindi alla fine l'array viene riempito con puntatori identici e così ottieni un comportamento identico.


0 per risposta № 4

Nota: È necessario specificare copy come attributo della proprietà, poiché un blocco deve essere copiato per tenere traccia del suo stato acquisito al di fuori dell'ambito originale. Questo non è qualcosa di cui ti devi preoccupare quando utilizzi il conteggio automatico dei riferimenti, poiché avverrà automaticamente, ma è consigliabile che l'attributo di proprietà mostri il comportamento risultante. Per ulteriori informazioni, vedere Blocchi Argomenti di programmazione.


-1 per risposta № 5

Per quanto ho capito copy è richiesto quando l'oggetto è mutabile. Usa questo se hai bisogno del valore dell'oggetto così com'è in questo momento e non vuoi che quel valore rifletta le modifiche apportate da altri proprietari dell'oggetto. Dovrai rilasciare l'oggetto quando hai finito con esso perché stai conservando la copia.

D'altro canto, strong significa che sei il proprietario dell'oggetto finché non è necessario. È un sostituto per retain attributo, come parte di ARC.

Fonte: Objective-C ha dichiarato attributi @property (non atomico, copy, strong, weak)