July 15, 2015

ทำความรู้จักกับ defer ใน Swift 2

คำสั่ง defer ถูกเพิ่มเข้ามาใน Swift 2 คำสั่งนี้ช่วยการันตีได้ว่าโค้ดที่อยู่ในบล็อคที่ประกาศโดยใช้ defer จะทำงานก่อนจบฟังก์ชัน, เม็ดธ็อด หรือ scope เสมอ

ดูตัวอย่างปัญหา


จากตัวอย่าง ฟังก์ชันจะเปิดไฟล์ จากนั้นตรวจสอบและเขียนข้อมูลโดยใช้ guard (ทำความรู้จักกับ guard ใน Swift 2) และบรรทัดสุดท้ายสั่งปิดไฟล์

แต่จะเกิดอะไรขึ้นหากสิ่งที่นำมาเขียนลงไฟล์มีปัญหา และทำให้ต้องจบฟังก์ชันก่อนสั่งปิดไฟล์ แน่นอนว่าไฟล์ไม่ถูกปิดและไฟล์ถูกเปิดทิ้งไว้อยู่อย่างนั้น

ทางแก้ของปัญหานี้ทำได้ 2 ทาง คือ เขียนคำสั่งปิดไฟล์ไว้ก่อน return ทุกๆ อัน และอีกทางหนึ่งคือทำ Pyramid of Doom ซึ่งทั้ง 2 ทางที่กล่าวถึง ล้วนไม่ใช่ทางออกที่ดีนัก แล้วทางออกไหนล่ะที่ดีกว่า?

Swift 2 แก้ปัญหานี้ด้วยคำสั่ง defer

คำสั่ง defer เป็นการบอกว่า "ไม่ว่ามันคืออะไร นี่คือสิ่งที่เราจะต้องทำก่อนจบ scope เสมอ"

เราสามารถใช้ defer เข้ามาแก้ปัญหาจากตัวอย่างข้างต้นได้แบบนี้


เมื่อเราบรรจุคำสั่งปิดไฟล์ไว้ในโค้ดบล็อคที่ประกาศโดย deferแล้ว ไม่ว่า guard จะ trigger ตอนไหน หรือไม่ trigger เลยก็ตาม ก่อนจบฟังก์ชันนี้ โค้ดในบล็อก defer จะถูกทำงานเสมอ ทำให้เราสามารถรับประกันได้ว่า ไม่ว่าจะจบการทำงานของฟังก์ชันตอนไหน ไฟล์จะถูกปิดแน่นอน

ยกตัวอย่างอีกอัน


โปรแกรมจะพิมพ์ "Step 1", "Step 2", "Step 4", "Step 3", "Step 5"

โค้ดในบล็อก defer จะทำงานเสมอเมื่อจะจบฟังก์ชัน, เม็ดธ็อด, หรือ scope ใดๆ (ที่อยู่ระหว่าง {...}) ในกรณีทั่วไปก็จะถูกใช้ในบล็อกของ do และ loop ต่างๆ

เราสามารถใช้ do ในการสร้าง scope ชั่วคราวที่ไหนก็ได้ในเม็ดธ็อด และหากเราใช้ defer ในบล็อค do แล้ว defer จะทำงานทันทีที่บล็อค do จบ โดยไม่จำเป็นต้องรอให้จบฟังก์ชัน ยกตัวอย่างเช่น


เมื่อรันโปรแกรมจะพิมพ์ 1, 3, 4, 2, 5 เพราะการพิมพ์ 2 ถูก defer ให้ไปทำงานตอนจบบล็อค do

เราสามารถประกาศบล็อค defer ได้มากกว่า 1 แห่งใน scope เดียวกัน โดยที่ Swift ยังคงรับประกันว่าโค้ดในทุกบล็อค defer จะทำงานก่อนจบ scope โดยบล็อค defer ที่ถูกประกาศไว้ท้ายสุดจะทำงานก่อนบล็อค defer ที่ถูกประกาศไว้ก่อน

ตัวอย่าง


เราจะได้ output ดังนี้
We are doing other work
We are doing even more work
New Foo's Bar was Monkeys
Now it is nil
Original Foo's Bar was Lorem Ipsum 
Now it is nil

เราไม่สามารถใช้คำสั่งจบ scope เช่น return หรือ throw error ในบล็อค defer ได้

อ่านเพิ่ม: The defer keyword in Swift 2, The Swift 2.0 Defer Keyword
ภาพประกอบ Flickr, Some rights reserved