การเตรียมการสัมภาษณ์ iOS 3 — การบล็อกและการปิด
ภาพรวม
การปิดหรือการบล็อกเป็นหน่วยของรหัสที่สามารถส่งผ่านและดำเนินการได้ในภายหลัง พวกเขาทำงานคล้ายกับฟังก์ชั่นมาก แต่มีความยืดหยุ่นและมีประสิทธิภาพมากกว่า เนื่องจากสามารถส่งผ่านเป็นอาร์กิวเมนต์ไปยังฟังก์ชัน เก็บไว้ในตัวแปร และแม้แต่ใช้เป็นค่าส่งคืน
คำถามสัมภาษณ์
- สามารถบล็อกจับตัวแปรจากขอบเขตโดยรอบได้หรือไม่ อธิบายด้วยตัวอย่าง
- คุณจะหลีกเลี่ยงการสร้างวงจรอ้างอิงที่แข็งแกร่งได้อย่างไรเมื่อใช้การปิดหรือบล็อก
- คุณจะใช้
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
}
};