การทำความเข้าใจการนับอ้างอิงใน Cocoa และ Objective-C: คู่มือสำหรับผู้เริ่มต้นเกี่ยวกับการจัดการหน่วยความจำ
เมื่อคุณดำดิ่งสู่โลกของ Objective-C และ Cocoa โดยเฉพาะหากคุณสนใจในพัฒนาซอฟต์แวร์ iPhone SDK คุณอาจจะรู้สึกสับสนเกี่ยวกับการจัดการหน่วยความจำ—โดยเฉพาะระบบการนับอ้างอิง แม้ว่าคุณอาจจะคุ้นเคยกับ malloc
และ free
ใน C แต่แนวทางของ Cocoa ในการจัดการหน่วยความจำจะแตกต่างออกไปเล็กน้อย ในโพสต์นี้ เราจะสำรวจว่าสำหรับคำว่า retain
, release
และ autorelease
ทำงานอย่างไร และให้คำแนะนำที่เป็นประโยชน์ในการช่วยให้คุณเข้าใจแนวคิดเหล่านี้
Retain
, Release
, และ Autorelease
คืออะไร?
การทำความเข้าใจ retain
และ release
เป็นสิ่งพื้นฐาน เพราะมันเป็นเสาหลักของการจัดการหน่วยความจำใน Cocoa เราจะพูดคุยเกี่ยวกับ autorelease
ในภายหลัง เนื่องจากมันเป็นกรณีที่เฉพาะเจาะจงมากขึ้นซึ่งสร้างจากแนวคิดสองข้อแรก
อธิบาย Retain
และ Release
-
Retain: เมื่อคุณเรียกใช้
retain
กับวัตถุ คุณจะเพิ่มจำนวนอ้างอิงของมันขึ้นหนึ่งครั้ง ซึ่งบ่งบอกว่าคุณตั้งใจที่จะเก็บวัตถุไว้นานขึ้น -
Release: เมื่อคุณเรียกใช้
release
จำนวนอ้างอิงของวัตถุจะถูกลดลงหนึ่งครั้ง หากมันลดลงถึงศูนย์ ระบบจะทำการปล่อยหน่วยความจำที่วัตถุใช้งานอยู่
ความงามของระบบนี้อยู่ที่ความเรียบง่าย หลายส่วนในโปรแกรมสามารถอ้างอิงวัตถุเดียวกันได้โดยไม่ต้องกังวลเกี่ยวกับความล่มของหน่วยความจำ ขอเพียงแต่ทุกส่วนของโค้ดของคุณทำการ retain
และ release
วัตถุอย่างถูกต้องตามต้องการ ทุกอย่างจะคงอยู่ในสถานะที่มั่นคง
การจัดการหน่วยความจำ: กฎพื้นฐานที่เป็นประโยชน์
แนวทางทั่วไปใน Cocoa คือ:
- หากคุณเป็นเจ้าของวัตถุ (เช่น หากคุณจะใช้งานมันเกินกว่าฟังก์ชันหนึ่ง) ให้เรียกใช้
retain
เพื่อเพิ่มจำนวนอ้างอิงของมัน - เมื่อคุณเสร็จสิ้นกับวัตถุ ให้เรียกใช้
release
เพื่อแจ้งระบบว่ามันสามารถปล่อยหน่วยความจำได้
นี่คือตัวอย่างเพื่อช่วยให้เข้าใจ:
NSString* s = [[NSString alloc] init]; // จำนวนอ้างอิงเป็น 1
[s retain]; // จำนวนอ้างอิงเป็น 2
[s release]; // จำนวนอ้างอิงกลับมาเป็น 1
[s release]; // จำนวนอ้างอิงเป็น 0, วัตถุถูกปล่อย
Autorelease
: ทางลัดที่ช่วยได้
ตอนนี้มาจัดการกับ autorelease
ซึ่งวิธีนี้ให้วิธีการสะดวกในการจัดการหน่วยความจำโดยไม่ต้องเรียกใช้ release
โดยตรงหลังจากการสร้างวัตถุ
- เมื่อคุณเรียกใช้
autorelease
: จะทำการแจ้งNSAutoreleasePool
ของเธรดปัจจุบัน (กลไกที่จัดการวัตถุที่ถูก autoreleased) เพื่อปล่อยวัตถุในบางจุดในอนาคต—โดยปกติเมื่อสิ้นสุดการวนลูปเหตุการณ์ปัจจุบัน
กระบวนการจัดการหน่วยความจำอัตโนมัติ
NSString* s = [NSString stringWithString:@"Hello World"];
จุดที่สำคัญที่ต้องกล่าวถึงคือ เมธอดของคลาสเช่น stringWithString:
จะคืนค่าวัตถุที่ถูก autoreleased หากคุณต้องการเก็บสตริงนั้นไว้ คุณจะต้องเรียกใช้ retain
โดยเฉพาะ:
[s retain]; // ตอนนี้คุณมีการควบคุมเหนือวงจรชีวิตของมัน
เมื่อใดจึงควรใช้ Autorelease
ลองพิจารณาสถานการณ์ที่คุณสร้างวัตถุ แต่ไม่ต้องการให้ผู้เรียกจัดการหน่วยความจำโดยตรง นี่คือตัวอย่างฟังก์ชันที่แสดงให้เห็น:
- (NSString*)createHelloWorldString {
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// เพื่อหลีกเลี่ยงการจัดการหน่วยความจำที่สับสน ใช้ autorelease:
return [s autorelease]; // มอบความรับผิดชอบในการปล่อย
}
ที่นี่ คุณได้ส่งมอบความรับผิดชอบในการปล่อยสตริงไปยัง NSAutoreleasePool
ทำให้แน่ใจว่าสตริงที่คืนค่ามายังคงใช้งานได้โดยไม่สร้างภาระให้กับผู้เรียก
สรุป
แม้ว่าการจัดการหน่วยความจำใน Objective-C และ Cocoa อาจดูยากในตอนแรก แต่การเชี่ยวชาญใน retain
, release
, และ autorelease
จะให้พื้นฐานที่มั่นคงสำหรับการจัดการหน่วยความจำในการพัฒนา iOS นี่คือทรัพยากรบางอย่างที่สามารถช่วยให้คุณดำน้ำลึกขึ้น:
- การแนะนำการจัดการหน่วยความจำของ Apple
- การเขียนโปรแกรม Cocoa สำหรับ Mac OS X (ฉบับที่ 4) โดย Aaron Hillegas – หนังสือเล่มนี้เต็มไปด้วยตัวอย่างและอ่านเหมือนว่าเป็นบทเรียน
- Big Nerd Ranch มีหลักสูตรที่ยอดเยี่ยม ซึ่งสามารถช่วยให้คุณเข้าใจลึกซึ้งยิ่งขึ้น
ด้วยการฝึกฝน แนวคิดเหล่านี้จะเกิดขึ้นกับคุณในที่สุด! โค้ดอย่างมีความสุข!