การเตรียมการสัมภาษณ์ iOS 3 — การบล็อกและการปิด

May 01 2023
ภาพรวม การปิดหรือบล็อกเป็นหน่วยของรหัสที่สามารถส่งต่อและดำเนินการได้ในภายหลัง พวกเขาทำงานคล้ายกับฟังก์ชั่นมาก แต่มีความยืดหยุ่นและมีประสิทธิภาพมากกว่า

ภาพรวม

การปิดหรือการบล็อกเป็นหน่วยของรหัสที่สามารถส่งผ่านและดำเนินการได้ในภายหลัง พวกเขาทำงานคล้ายกับฟังก์ชั่นมาก แต่มีความยืดหยุ่นและมีประสิทธิภาพมากกว่า เนื่องจากสามารถส่งผ่านเป็นอาร์กิวเมนต์ไปยังฟังก์ชัน เก็บไว้ในตัวแปร และแม้แต่ใช้เป็นค่าส่งคืน

คำถามสัมภาษณ์

  • สามารถบล็อกจับตัวแปรจากขอบเขตโดยรอบได้หรือไม่ อธิบายด้วยตัวอย่าง
  • คุณจะหลีกเลี่ยงการสร้างวงจรอ้างอิงที่แข็งแกร่งได้อย่างไรเมื่อใช้การปิดหรือบล็อก
  • คุณจะใช้weakคำหลักในสถานการณ์ใด และคุณจะใช้unownedคำหลัก ในสถานการณ์ใด
  • จุดประสงค์ของ__blockตัวดัดแปลงในบล็อค Objective-C คืออะไร? อธิบายด้วยตัวอย่าง

บล็อกถูกนำมาใช้เป็นวัตถุประเภท Objective-C NSBlockซึ่งเป็นเพียงโครงสร้างที่มีisaตัวชี้ ตัวอักษรจะถูกแปลโดยตรงเป็นโครงสร้างโดยคอมไพเลอร์ แต่ละวัตถุบล็อกมีตัวชี้ไปยังรหัสปฏิบัติการ เช่นเดียวกับตัวแปรที่จับได้ซึ่งถูกอ้างอิงในบล็อก เมื่อบล็อกถูกสร้างขึ้น จะบันทึกสำเนาของค่าของตัวแปรใดๆ ภายในบล็อก ค่าที่บันทึกเหล่านี้จะถูกเก็บไว้จนกว่าบล็อกจะถูกยกเลิกการจัดสรร

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

การปิด/บล็อกสามารถจับและจัดเก็บการอ้างอิงถึงค่าคงที่และตัวแปรใดๆ จากบริบทโดยรอบซึ่งถูกกำหนด การจับภาพช่วยให้พวกเขาสามารถ "จัดแพ็คเกจ" และถ่ายภาพ "สแน็ปช็อต" ของสถานะขอบเขตการปิดล้อมปัจจุบัน

สิ่งนี้มีประสิทธิภาพเพราะช่วยให้การปิดการเข้าถึงและแก้ไขค่าในบริบทที่กำหนดไว้ สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อทำงานกับโค้ดแบบอะซิงโครนัส เนื่องจากช่วยให้การปิดสามารถเข้าถึงและแก้ไขค่าที่อาจมีการเปลี่ยนแปลงตามเวลาที่ดำเนินการปิด

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 จัดเตรียมคุณสมบัติทางไวยากรณ์ที่เรียกว่ารายการบันทึกที่ให้คุณระบุวิธีที่การปิดบันทึกค่าของตัวแปรที่ใช้ภายในการปิด

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 ประเภทดั้งเดิมจะถูกบันทึกเป็นประเภท const ที่ไม่เปลี่ยนรูป หากต้องการอัปเดตค่าของตัวแปรที่จับ คุณสามารถใช้__blockคีย์เวิร์ด สำหรับประเภทการอ้างอิง บล็อกจะรักษาการอ้างอิงที่แข็งแกร่งไปยังอ็อบเจ็กต์เหล่านั้น ซึ่งป้องกันไม่ให้ถูกยกเลิกการจัดสรรในขณะที่บล็อกยังคงใช้งานอยู่

เมื่อทำงานกับวัตถุที่เปลี่ยนแปลงได้ เช่น NSMutableArray

  • หากคุณต้องการเปลี่ยนเนื้อหาของตัวแปร คุณไม่จำเป็นต้องใช้ __block
  • ฉันต้องเปลี่ยนตัวแปรเอง จากนั้นคุณต้องใช้ __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()
        }
    }
}

และเมื่อมีการเรียกใช้บล็อก เราจะสร้างการอ้างอิงที่ชัดเจนให้กับการอ้างอิงตนเองที่อ่อนแอ ซึ่งช่วยให้คุณเข้าถึงselfได้จากภายในบล็อกโดยไม่ต้องกังวลว่าจะถูกยกเลิกการจัดสรรก่อนที่บล็อกจะเสร็จสมบูรณ์

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