เริ่มต้นด้วยretain
และrelease
; autorelease
เป็นเพียงกรณีพิเศษเมื่อคุณเข้าใจแนวคิดพื้นฐานแล้ว
ใน Cocoa แต่ละออบเจ็กต์จะติดตามว่ามีการอ้างอิงกี่ครั้ง (โดยเฉพาะNSObject
คลาสพื้นฐานจะใช้สิ่งนี้) การเรียกretain
ใช้วัตถุแสดงว่าคุณต้องการเพิ่มจำนวนการอ้างอิงทีละรายการ เมื่อเรียกrelease
คุณจะบอกวัตถุที่คุณปล่อยมันไปและจำนวนการอ้างอิงจะลดลง หากหลังจากการเรียกrelease
จำนวนการอ้างอิงตอนนี้เป็นศูนย์ดังนั้นหน่วยความจำของวัตถุนั้นจะถูกปลดปล่อยโดยระบบ
วิธีพื้นฐานนี้แตกต่างจากmalloc
และfree
เป็นว่าวัตถุใดก็ตามไม่จำเป็นต้องกังวลเกี่ยวกับส่วนอื่น ๆ ของระบบ crashing เพราะคุณได้ปลดปล่อยหน่วยความจำที่พวกเขาใช้ สมมติว่าทุกคนเล่นตามและรักษา / ปล่อยตามกฎเมื่อโค้ดชิ้นหนึ่งเก็บรักษาและปล่อยวัตถุชิ้นส่วนอื่น ๆ ของโค้ดที่อ้างถึงวัตถุนั้นจะไม่ได้รับผลกระทบ
สิ่งที่บางครั้งอาจจะทำให้เกิดความสับสนคือรู้ว่าภายใต้สถานการณ์ที่คุณควรจะเรียกและretain
release
หลักการทั่วไปของฉันคือถ้าฉันต้องการแขวนอยู่กับวัตถุเป็นระยะเวลาหนึ่ง (เช่นถ้าเป็นตัวแปรสมาชิกในคลาส) ฉันต้องตรวจสอบให้แน่ใจว่าจำนวนการอ้างอิงของวัตถุรู้เกี่ยวกับฉัน retain
ตามที่อธิบายไว้ข้างต้นนับอ้างอิงของวัตถุจะเพิ่มขึ้นโดยการโทร ตามแบบแผนมันจะเพิ่มขึ้นด้วย (ตั้งค่าเป็น 1 จริง ๆ ) เมื่อวัตถุถูกสร้างด้วยเมธอด "init" ในทั้งสองกรณีนี้เป็นความรับผิดชอบของฉันที่จะเรียกร้องrelease
ให้วัตถุเมื่อฉันทำเสร็จแล้ว ถ้าฉันไม่ทำจะมีความทรงจำรั่วไหล
ตัวอย่างการสร้างวัตถุ:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
ตอนนี้สำหรับautorelease
. Autorelease ใช้เป็นวิธีที่สะดวก (และบางครั้งจำเป็น) เพื่อบอกให้ระบบปล่อยวัตถุนี้ให้เป็นอิสระหลังจากนั้นสักครู่ จากมุมมองของระบบประปาเมื่อautorelease
ถูกเรียกเธรดปัจจุบันNSAutoreleasePool
จะได้รับการแจ้งเตือนเมื่อมีการโทร NSAutoreleasePool
ตอนนี้รู้ว่าเมื่อได้รับโอกาส (หลังจากย้ำปัจจุบันของห่วงเหตุการณ์) ก็สามารถเรียกrelease
บนวัตถุ จากมุมมองของเราในฐานะโปรแกรมเมอร์มันดูแลเรียกร้องrelease
ให้เราดังนั้นเราไม่จำเป็นต้องทำ (และในความเป็นจริงเราไม่ควร)
สิ่งสำคัญที่ควรทราบคือ (อีกครั้งตามแบบแผน) เมธอดคลาสการสร้างอ็อบเจ็กต์ทั้งหมดจะส่งคืนอ็อบเจ็กต์ที่ปล่อยออกมาโดยอัตโนมัติ ตัวอย่างเช่นในตัวอย่างต่อไปนี้ตัวแปร "s" มีจำนวนการอ้างอิงเป็น 1 แต่หลังจากการวนซ้ำของเหตุการณ์เสร็จสมบูรณ์ตัวแปรจะถูกทำลาย
NSString* s = [NSString stringWithString:@"Hello World"];
หากคุณต้องการแขวนสายนั้นคุณจะต้องโทรretain
อย่างชัดเจนจากนั้นจึงพูดอย่างชัดเจนrelease
เมื่อคุณทำเสร็จแล้ว
พิจารณาบิตโค้ดต่อไปนี้ (ที่สร้างขึ้นอย่างมาก) และคุณจะเห็นสถานการณ์ที่autorelease
จำเป็น:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
ฉันรู้ว่าทั้งหมดนี้ค่อนข้างสับสน - ในบางครั้งมันจะคลิก นี่คือข้อมูลอ้างอิงบางส่วนที่จะช่วยให้คุณดำเนินการต่อไป:
- คำแนะนำของ Apple เกี่ยวกับการจัดการหน่วยความจำ
- Cocoa Programming สำหรับ Mac OS X (รุ่นที่ 4)โดย Aaron Hillegas - หนังสือที่เขียนดีมากพร้อมตัวอย่างดีๆมากมาย มันอ่านเหมือนบทช่วยสอน
- ถ้าคุณอยู่ในการดำน้ำอย่างแท้จริงคุณสามารถมุ่งหน้าไปยังไร่ Nerd บิ๊ก นี่คือสถานที่ฝึกอบรมที่ดำเนินการโดย Aaron Hillegas - ผู้เขียนหนังสือที่กล่าวถึงข้างต้น ฉันเข้าเรียนหลักสูตร Intro to Cocoa ที่นั่นเมื่อหลายปีก่อนและเป็นวิธีที่ดีในการเรียนรู้