iOS Mülakat Hazırlığı 3 — Bloklar ve Kapanışlar

May 01 2023
Genel Bakış Kapatma veya blok, daha sonra aktarılabilen ve çalıştırılabilen bir kod birimidir. İşlevlere çok benzer şekilde davranırlar, ancak daha esnek ve güçlüdürler.

genel bakış

Kapatma veya engelleme, daha sonra iletilebilen ve yürütülebilen bir kod birimidir. İşlevlere çok benzer şekilde davranırlar, ancak daha esnek ve güçlüdürler. Çünkü işlevlere argüman olarak iletilebilirler, değişkenlerde saklanabilirler ve hatta dönüş değerleri olarak kullanılabilirler.

Görüşme soruları

  • Bloklar, çevre kapsamlarından değişkenleri yakalayabilir mi? Bir örnekle açıklayınız.
  • Kapatma veya blok kullanırken güçlü bir referans döngüsü oluşturmaktan nasıl kaçınabilirsiniz?
  • Anahtar kelimeyi hangi durumlarda kullanırsınız weakve hangi durumlarda anahtar kelimeyi kullanırsınız unowned?
  • __blockObjective-C bloklarındaki değiştiricinin amacı nedir ? Bir örnekle açıklayınız.

NSBlockBloklar, sadece bir işaretçi ile yapılan yapılar olan Objective-C tipi nesneler olarak uygulanır isa. Değişmez değerler, derleyici tarafından doğrudan yapılara çevrilir. Her blok nesnesi, yürütülebilir koda bir işaretçi ve ayrıca blokta başvurulan yakalanan değişkenleri içerir. Bir blok oluşturulduğunda, blok içindeki herhangi bir değişkenin değerlerinin bir kopyasını yakalar. Yakalanan bu değerler, blok yeniden konumlandırılana kadar korunur.

^ { 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 }

Bir kapatma/blok, tanımlandığı çevreleyen bağlamdan herhangi bir sabite ve değişkene yapılan başvuruları yakalayabilir ve depolayabilir. Yakalama, mevcut kapsama kapsamı durumunun "paketlenmesine" ve "anlık görüntüsünü" almasına olanak tanır.

Bu güçlüdür, çünkü bir kapatmanın tanımlandığı bağlamdaki değerlere erişmesini ve bunları değiştirmesini sağlar. Bu, eşzamansız kodla çalışırken özellikle yararlı olabilir, çünkü bir kapatmanın yürütüldüğü zamana kadar değişmiş olabilecek değerlere erişmesine ve bunları değiştirmesine izin verir.

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, bir kapatmanın, kapatma içinde kullanılan değişkenlerin değerlerini nasıl yakaladığını belirtmenize izin veren, yakalama listesi adı verilen bir sözdizimi özelliği sağlar.

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()

Objective-C'de, ilkel tipler sabit sabit tipler olarak yakalanır. Yakalanan değişkenlerin değerlerini güncellemek için anahtar kelimeyi kullanabilirsiniz __block. Referans türleri için blok, bu nesnelere yönelik güçlü bir referansı koruyacak ve bu, blok kullanımdayken bunların yeniden konumlandırılmasını önleyecektir.

Değişken nesnelerle çalışırken, örneğin bir NSMutableArray

  • Değişkenin içeriğini değiştirmeniz gerekirse, __block kullanmanıza gerek yoktur.
  • Değişkenin kendisini değiştirmeniz gerekiyorsa, o zaman __block kullanmanız gerekir.
  • 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()
        }
    }
}

Ve blok çağrıldığında, zayıf öz referansa güçlü bir referans yaratırız. selfBu , blok tamamlanmadan önce yeniden konumlandırılmasından endişe duymadan bloğun içinden erişmenizi sağlar .

__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
  }
};