Memory Management Basic(Weak, Unowned and Closure) — Part I Weak​Type

Apinun (Nun) Wongintawang
te<h @TDG
Published in
3 min readApr 6, 2020
Pic by ถ่ายกับเสี่ย

เนื้อหาของบทความนี้จะเป็นการใช้งาน weak เพื่อจัดการในเรื่องของ Memory โดยตัวอย่างในบทความนี้จะมีการอ้างอิงถึงภาพยนตร์เรื่อง Avenger ของ ค่าย Marvel เล็กน้อยนะครับ

ปกติ iOS ตั้งแต่เปลี่ยนจาก Objective C มาเป็นภาษา Swift จะมีการจัดการเรื่องหน่วยความจำให้ที่เรียกว่า Automatic Reference Counting (ARC) โดย ARC จะทำการ allocates และ Deallocate ค่า memory ให้แบบอัตโนมัติ แต่ไม่ใช่ทั้งหมด จะมีส่วนที่ Programmer ต้องมาจัดการเรื่อง Memory เอง นั่นคือการเชื่อมโยงกัน(Relation) ของ Object หรือ โมเดลที่เราคุ้นเคยกันนั่นเอง

โดยค่า Default ทั่วไปของการประกาศ Object ขึ้นมาซักตัวหนึ่ง จะได้ประเภทของ Object เป็น Strong type เสมอ ซึ่งตัวแปรประเภทนี้เมื่อมีหลาย Object เชื่อมกันบางครั้งจะคืนค่าหน่วยความจำไม่หมดและทำให้เกิดการจองพื้นที่หน่วยความจำไว้ และการเกิด Strong Type จะเป็นเฉพาะตัวแปที่เป็น Class เท่านั้นนะครับ Struct จะไม่เกิดขึ้นเพราะ Struct หลักการมันการจองหน่วยความจำที่มีพื้นที่ไม่จำกัด พูดด้วยข้อความอาจจะไม่เห็นภาพเรามาลุยกันเลยดีกว่าครับ

มาทำความเข้าใจเรื่อง Strong Type ก่อน

อย่างที่บอกหัวข้อที่แล้วครับ ค่า Default ของตัวแปรคือ Strong Type โดยโฟลวการจองพื้นที่หน่วยความจำจะเป็นดังนี้

จากรูปจะมี Objec อยู่สองตัวคือ Hero และ Villian(ตัวร้าย) ซึ่งเมื่อมีการสร้าง Object ขึ้นมาคือ Dr. Strange และ Thanos ตอนนี้จะมีการจองหน่วยความจำเกิดขึ้นเรียบร้อยครับ (mem: 2)

Step 1 Create 2 Object

หลังจากจบศึกแรกฝั่ง Dr. Strange พลาดท่าให้กับ Thanos ทำให้ถูกทำลาย Object ไปแต่ว่าค่า Reference Memory ยังไม่กลายเป็น 0 เพราะว่า Object ของ Dr. Strange ถูกประกาศเป็นค่า Strong Type นั่นเอง

ทุกคนเริ่มเห็นแล้วใช่ไหมครับว่า การประกาศตัวแปรแต่ละตัวนั้น มันทำให้เกิดการจอง Memory เกิดขึ้นและไม่คืนค่า Reference Count ให้ Memory ถ้ามี Object แบบนี้ประมาณ​20 -30 ตัวจะเกิดอะไรขึ้นบ้างแอพฯจะมีการบริโภค memory เยอะมากๆเลยครับ

มารู้จักกับ Weak หนึ่งในพระเอกของเรากัน

คุณสมบัติของ Weak จะมีอยู่ 2 อย่างคือ

  1. ตัวเแปรจะต้องเป็น Optional Type ซึ่งสามารถตั้งค่า nil (Null Object) ได้
  2. เมื่อไม่ได้ใช้งาน Weak Object จะสามารถคืนค่า Reference โดยอัติโนมัติ

โฟลวจะทำงานของตัวแปรประเภทนี้ จะเป็นตามนี้ครับผม

ขั้นตอนแรกเราสร้าง Black Widow ขึ้นมานะครับ และกำหนด ​Type เป็น Weak และสร้าง Thanos(Multiverse) ยังเป็น Strong Type เหมือนเดิมเมื่อนำสอง Object มาเชื่อมความสัมพันธ์(Relation) จะเห็นดังรูปครับ

step 1

จากนั้นหลังจากมีการห้ำหั่นกัน Black Widow เสียสละตัวเองเพื่อให้ได้ Soul Stone ทำให้ Black Widow Object ถูกทำลายลงไปและไม่สามารถฟื้นคืนชีพได้ด้วยการดีดนิ้ว ถ้าพูดในการเชิงโปรแกรมมิ่งคือ ตัวแปร Black Widow ถูกทำลายลงไป และคืนพื้นที่หน่วยความจำทั้งหมดให้แก่ Memory นั่นเอง ดังภาพข้างล่าง

step 2

เข้าใจ Concept แล้วมาลองเขียนโปรแกรมกัน เปิด PlayGround ขึ้นมาเลยครับ

Load Start Project ได้ ที่นี่ ครับ

ขั้นตอนแรก สร้าง Object ขึ้นมาก่อน

Step 1 Create Object

มาทดลองสร้าง Object ซักตัวครับ เมื่อลองกด Build จะได้ผลลัพธ์ดังนี้

จาก ตัวอย่างโค้ดเมื่อทำการ init ค่าในบรรทัดที่ 16 ภายในฟังก์ชั่น do {} และเมื่อจบการ Build จะทำการคืนค่า Marvel object ดังรูป แน่นอนมันต้องคืนค่าหน่วยความจำให้อยู่แล้วเพราะสร้าง Object มาแค่ตัวเดียวนี่!!!

ขั้นตอนที่ 2 มาสร้าง Object และสร้างความสัมพันธ์กันระหว่าง Object กัน

ขั้นตอนนี้เราจะสร้าง Object มาสองตัวนะครับและใส่ความสัมพันธ์ให้มัน

step 2 Create Avenger team Object and stone Object
let stonesName = ["Space Stone", "Soul Stone", "Reality Stone", "Time Stone", "Power Stone"]    
var stones = stonesName.map({StoneObjcet($0)})
let captainTeam = AvengerTeamObject(name: "Team Captain", stones: stones)

จาก Source Code ส่วนข้างบนจะเห็นว่า มีการสร้าง Stone Object ขึ้นมาหลายตัวและนำ Stone Object เก็บไว้ในตัวแปลที่ชื่อว่า stones

จากนั้นสร้าง Object Team ของ captain Team เพื่อนำ Stones มาเก็บไว้ที่ทีมนี้ และระบุทีมที่เป็นเจ้าของ Stone แต่ละชิ้นไว้ด้วย ตอนนี้ถ้าทำเป็น โมเดลความสัมพันธ์จะได้ดังรูป

ความสัมพันธ์จาก Source Code ข้างบน

จะเห็นว่า Object คือ Strong type ทั้งหมดเมื่อ ทำการ Build ออกมาผลลัพธ์ที่ได้คือ

จะเห็นว่าไม่มีการเรียกคืนหน่วยความจำเลย (Deinit)

จะทำอย่างไรดีให้ CaptainTeam Object คืนหน่วยความจำหละ

เราต้องเปลี่ยนความสัมพันธ์ของ Object ใหม่ ทำการกำหนด Weak type ให้กับตัวแปร ownerTeam เพื่อให้ ARC เรียกคืนหน่วยความจำหลังจากจบการปฏิบัติการณ์ครั้งนี้

แก้บรรทัดที่ 18 ตามนี้ครับ

weak var ownerTeam: MarvelObject?

มาดูผลลัพธ์กัน

ตอนนี้จะเห็นว่ามีการเรียกคืนหน่วยความจำแล้ว และ Graph ความสัมพันธ์ของโมเดลจะเปลี่ยนเป็นดังนี้

After Added weak type to object

สรุป

จากข้อมูลเบื้องต้นจะเห็นกันแล้วนะครับว่า ARC ไม่ได้ทำการคืนค่า Memory ให้เอง ยังมีส่วนที่ Programmer ต้องจัดการกันต่อเอง โดยการจัดการความสัมพันธ์ระหว่าง Object เป็นการจัดการที่ค่อนข้างต้องให้ความสำคัญอย่างมาก ซึ่งทำให้ แอพฯที่เราสร้างนั้นเร็วและเสถียรมากขึ้น และอาจทำให้เกิดปัญหา Memory Leak หรือ App Crash ขึ้นได้ถ้าหน่วยความจำไม่เพียงพอ แต่ว่าส่วนที่มาจัดการหน่วยความจำไม่ได้มีแต่ Weak นะครับยังมี Unowned อีกอย่างหนึ่งซึ่งมาต่อใน PartII เร็วๆนี้ครับ

รบกวนฝากทำแบบสอบถามเกี่ยวกับบทความนี้หน่อยครับเพื่อนนำไปปรับปรุงต่อไปครับ ขอบคุณล่วงหน้ามา ณ.ที่นี่ด้วยครับ 🙏🏻🙏🏻🙏🏻

https://forms.gle/rkNzHeZoJ1vViA59A

Reference

--

--