iOS Interview Prep 3 - Blocchi e chiusure
Panoramica
Chiusura o blocco è un'unità di codice che può essere passata ed eseguita in un secondo momento. Si comportano in modo molto simile alle funzioni, ma sono più flessibili e potenti. Perché possono essere passati come argomenti a funzioni, archiviati in variabili e persino usati come valori di ritorno.
Domande di un'intervista
- I blocchi possono acquisire variabili dal loro ambito circostante? Spiega con un esempio.
- Come evitare di creare un forte ciclo di riferimento quando si utilizza una chiusura o un blocco?
- In quali situazioni useresti la
weakparola chiave e in quali situazioni useresti launownedparola chiave? - Qual è lo scopo del
__blockmodificatore nei blocchi Objective-C? Spiega con un esempio.
I blocchi sono implementati come oggetti Objective-C di tipo NSBlocksono solo strutture con un isapuntatore. I letterali vengono tradotti direttamente in struct dal compilatore. Ogni oggetto blocco contiene un puntatore al codice eseguibile, nonché qualsiasi variabile catturata a cui si fa riferimento nel blocco. Quando viene creato un blocco, acquisisce una copia dei valori di qualsiasi variabile all'interno del blocco. Questi valori acquisiti vengono mantenuti fino a quando il blocco non viene deallocato.
^ { printf("hello world\\n"); }
struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *);
struct __block_descriptor_1 *descriptor;
};
void __block_invoke_1(struct __block_literal_1 *_block) {
printf("hello world\\n");
}
static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 }
Una chiusura/blocco può acquisire e memorizzare riferimenti a qualsiasi costante e variabile dal contesto circostante in cui è definita. Capture consente loro di "impacchettare" e acquisire un'"istantanea" dell'attuale stato dell'ambito di inclusione.
Questo è potente perché consente a una chiusura di accedere e modificare i valori nel contesto in cui è definita. Ciò può essere particolarmente utile quando si lavora con codice asincrono, perché consente a una chiusura di accedere e modificare valori che potrebbero essere cambiati al momento dell'esecuzione della chiusura.
let url = URL(string: "<https://www.example.com>")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
DispatchQueue.main.async {
self.updateUI(with: data)
}
}
task.resume()s
Swift fornisce una funzionalità di sintassi chiamata elenco di acquisizione che consente di specificare in che modo una chiusura acquisisce i valori delle variabili utilizzate all'interno della chiusura.
let val = 5
// Create a closure that increments the value of val
let myClosure = { [val] in
// The closure captures the original value of val
print("Original value of val: \\(val)")
}
val += 10
myClosure()
In Objective-C, i tipi primitivi vengono acquisiti come tipi const immutabili. Per aggiornare i valori delle variabili acquisite, è possibile utilizzare la __blockparola chiave. Per i tipi di riferimento, block manterrà un forte riferimento a quegli oggetti, impedendo loro di essere deallocati mentre il blocco è ancora in uso.
Quando si lavora con oggetti mutabili, ad esempio un NSMutableArray
- Se è necessario modificare il contenuto della variabile, non è necessario utilizzare __block
- Se hai bisogno di cambiare la variabile stessa, allora devi usare __block
int val = 5;
__block int mutableVal = 5;
// Create a block that increments the value of val
void (^myBlock)(void) = ^{
val++;
mutableVal++;
};
// Call the block, which will increment the value of val
myBlock();
// Print the value of val to the console
NSLog(@"Value of val inside block: %d", val); // This prints 5
NSLog(@"Value of val inside block: %d", mutableVal); // This prints 6
class MyClass {
var myClosure: (() -> Void)?
func someMethod() {
myClosure = { [weak self]
guard let strongSelf = self else { return }
strongSelf.doSomething()
}
}
}
E quando il blocco viene invocato, creiamo un forte riferimento al debole autoreferenzialità. Ciò ti consente di accedere selfdall'interno del blocco, senza preoccuparti che venga deallocato prima del completamento del blocco.
__weak typeof(self) weakSelf = self;
void (^myBlock)(void) = ^{
// Maintain a strong reference to self to keep it in memory
__strong typeof(self) strongSelf = weakSelf;
// Check if self has been deallocated, if so return
if (strongSelf) {
// Do something
}
};
![Che cos'è un elenco collegato, comunque? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































