iOS Interview Prep 3 - Blocages et fermetures
Aperçu
La fermeture ou le bloc est une unité de code qui peut être transmise et exécutée ultérieurement. Ils se comportent de manière très similaire aux fonctions, mais ils sont plus flexibles et puissants. Parce qu'ils peuvent être passés comme arguments à des fonctions, stockés dans des variables et même utilisés comme valeurs de retour.
Questions d'entretien
- Les blocs peuvent-ils capturer des variables de leur périmètre environnant ? Expliquez avec un exemple.
- Comment pouvez-vous éviter de créer un cycle de référence fort lors de l'utilisation d'une fermeture ou d'un blocage ?
- Dans quelles situations utiliseriez-vous le
weakmot-clé, et dans quelles situations utiliseriez-vous leunownedmot-clé ? - Quel est le but du
__blockmodificateur dans les blocs Objective-C ? Expliquez avec un exemple.
Les blocs sont implémentés en tant qu'objets Objective-C de type NSBlockce ne sont que des structures avec un isapointeur. Les littéraux sont directement traduits en structures par le compilateur. Chaque objet bloc contient un pointeur vers le code exécutable, ainsi que toutes les variables capturées qui ont été référencées dans le bloc. Lorsqu'un bloc est créé, il capture une copie des valeurs de toutes les variables à l'intérieur du bloc. Ces valeurs capturées sont conservées jusqu'à ce que le bloc soit désalloué.
^ { 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 }
Une fermeture/un bloc peut capturer et stocker des références à toutes les constantes et variables du contexte environnant dans lequel il est défini. La capture leur permet de « regrouper » et de prendre un « instantané » de l'état actuel de la portée englobante.
Ceci est puissant car il permet à une fermeture d'accéder et de modifier des valeurs dans le contexte dans lequel elle est définie. Cela peut être particulièrement utile lorsque vous travaillez avec du code asynchrone, car cela permet à une fermeture d'accéder et de modifier des valeurs qui peuvent avoir changé au moment où la fermeture est exécutée.
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 fournit une fonctionnalité de syntaxe appelée la liste de capture qui vous permet de spécifier comment une fermeture capture les valeurs des variables utilisées dans la fermeture.
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()
En Objective-C, les types primitifs sont capturés en tant que types const immuables. Pour mettre à jour les valeurs des variables capturées, vous pouvez utiliser le __blockmot-clé. Pour les types de référence, le bloc conservera une référence forte à ces objets, ce qui les empêchera d'être désalloués pendant que le bloc est encore utilisé.
Lorsque vous travaillez avec des objets modifiables, par exemple un NSMutableArray
- Si vous avez besoin de muter le contenu de la variable, vous n'avez pas besoin d'utiliser __block
- Si vous devez modifier la variable elle-même, vous devez utiliser __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()
}
}
}
Et lorsque le bloc est invoqué, nous créons une référence forte à la référence auto faible. Cela vous permet d'accéder selfdepuis l'intérieur du bloc, sans vous soucier qu'il soit désalloué avant la fin du bloc.
__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
}
};![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































