การทำความเข้าใจการนับอ้างอิงด้วย Cocoa และ Objective-C


122

ฉันเพิ่งเริ่มดู Objective-C และ Cocoa ด้วยมุมมองในการเล่นกับ iPhone SDK ฉันพอใจกับแนวคิดmallocและfreeแนวคิดของ C พอสมควรแต่รูปแบบการนับการอ้างอิงของ Cocoa ทำให้ฉันค่อนข้างสับสน ฉันบอกแล้วว่ามันสวยมากเมื่อคุณเข้าใจ แต่ฉันยังไม่เกินโคก

วิธีทำrelease, retainและautoreleaseการทำงานและสิ่งที่มีการประชุมเกี่ยวกับการใช้ของพวกเขา?

(หรือล้มเหลวคุณอ่านอะไรที่ช่วยให้คุณได้รับมัน)

คำตอบ:


148

เริ่มต้นด้วย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 ที่นั่นเมื่อหลายปีก่อนและเป็นวิธีที่ดีในการเรียนรู้

8
คุณเขียนว่า: "ด้วยการเรียกการปล่อยอัตโนมัติเราจะเพิ่มจำนวนอ้างอิงชั่วคราว" ฉันคิดว่ามันผิด การปล่อยอัตโนมัติจะทำเครื่องหมายเฉพาะวัตถุที่จะปล่อยในอนาคต แต่จะไม่เพิ่มจำนวนการอ้างอิง: cocoadev.com/index.pl?AutoRelease
LKM

2
"ตอนนี้สำหรับการปล่อยอัตโนมัติแล้ว Autorelease ถูกใช้เป็นวิธีที่สะดวก (และบางครั้งจำเป็น) เพื่อบอกให้ระบบปล่อยวัตถุนี้ให้เป็นอิสระหลังจากนั้นสักครู่" ในฐานะที่เป็นประโยคนำในสิ่งนี้ไม่ถูกต้อง มันไม่ได้บอกให้ระบบ "ว่าง [มัน] ขึ้น" มันบอกให้ลดจำนวนการกักเก็บ
mmalc

3
ขอบคุณมากสำหรับคำอธิบายที่ดี เพียงสิ่งเดียวที่ยังไม่มีความชัดเจน ถ้าNSString* s = [[NSString alloc] initWithString:@"Hello World"];ส่งคืนวัตถุที่ปล่อยอัตโนมัติ (ตามที่คุณเขียน) ทำไมฉันต้องทำreturn [s autorelease];และตั้งค่าเป็น "autorelease" อีกครั้งไม่ใช่แค่return s?
znq

3
@ Stefan: [[NSString alloc] initWithString:@"Hello World"]จะไม่ส่งคืนวัตถุที่ปล่อยอัตโนมัติ เมื่อใดก็ตามที่allocถูกเรียกจำนวนการอ้างอิงจะถูกกำหนดเป็น 1 และเป็นความรับผิดชอบของรหัสนั้นในการตรวจสอบให้แน่ใจว่าได้รับการเผยแพร่ ในทางกลับกันการ[NSString stringWithString:]โทรจะส่งคืนอ็อบเจ็กต์ที่ปล่อยอัตโนมัติ
Matt Dillard

6
เรื่องไม่สำคัญ: เนื่องจากคำตอบใช้ @ "" และ NSString สตริงจึงคงที่ตลอดดังนั้นจำนวนคงที่แน่นอนจะเป็นทั้งค่าคงที่และไม่เกี่ยวข้องทั้งหมด .... ไม่ได้ทำให้คำตอบผิดไม่ว่าจะด้วยวิธีใดก็ตามเพียง ตอกย้ำความจริงที่ว่าการรักษาจำนวนที่แน่นอนไม่เคยเป็นสิ่งที่คุณควรกังวล
bbum

10

หากคุณเข้าใจกระบวนการเก็บรักษา / เผยแพร่แล้วมีกฎทองสองข้อที่ "duh" ชัดเจนสำหรับโปรแกรมเมอร์ Cocoa ที่จัดตั้งขึ้น แต่น่าเสียดายที่ไม่ค่อยมีการสะกดคำนี้อย่างชัดเจนสำหรับผู้มาใหม่

  1. หากฟังก์ชั่นซึ่งจะส่งกลับวัตถุมีalloc, createหรือcopyในชื่อแล้ววัตถุเป็นของคุณ คุณต้องโทร[object release]เมื่อคุณทำเสร็จแล้ว หรือCFRelease(object)ถ้าเป็นวัตถุ Core-Foundation

  2. หากไม่มีคำเหล่านี้ในชื่อแสดงว่าวัตถุนั้นเป็นของคนอื่น คุณต้องโทร[object retain]หากคุณต้องการเก็บวัตถุไว้หลังจากสิ้นสุดฟังก์ชันของคุณ

คุณจะได้รับบริการที่ดีในการปฏิบัติตามอนุสัญญานี้ในฟังก์ชันที่คุณสร้างขึ้นเอง

(Nitpickers: ใช่มีการเรียก API บางตัวที่เป็นข้อยกเว้นของกฎเหล่านี้ แต่หายาก)


11
สิ่งนี้ไม่สมบูรณ์และไม่ถูกต้อง ฉันยังคงไม่เข้าใจว่าทำไมผู้คนถึงพยายามทำกฎซ้ำแทนที่จะชี้ไปที่เอกสารที่เกี่ยวข้อง: developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/…
mmalc

4
โดยเฉพาะอย่างยิ่งกฎของ Core Foundation นั้นแตกต่างจากของ Cocoa; ดูdeveloper.apple.com/documentation/CoreFoundation/Conceptual/…
mmalc

1
ฉันก็ไม่เห็นด้วย หากฟังก์ชันส่งคืนสิ่งที่ไม่ต้องการเป็นของตัวเองควรปล่อยให้ฟังก์ชันนั้นอัตโนมัติ เป็นผู้เรียกใช้งานฟังก์ชันเพื่อรักษามันไว้ (ถ้าต้องการ) ไม่ควรมีอะไรเกี่ยวข้องกับชื่อของวิธีการใด ๆ ที่ถูกเรียกใช้ นั่นคือการเข้ารหัสรูปแบบ C เพิ่มเติมซึ่งการเป็นเจ้าของวัตถุไม่ชัดเจน
แซม

1
ขออภัย! ฉันคิดว่าฉันเร่งรีบในการลงคะแนน กฎการจัดการหน่วยความจำคำตอบของคุณเกือบจะอ้างอิงถึง apple doc
แซม

8

หากคุณกำลังเขียนโค้ดสำหรับเดสก์ท็อปและคุณสามารถกำหนดเป้าหมายเป็น Mac OS X 10.5 ได้อย่างน้อยคุณควรพิจารณาการใช้การรวบรวมขยะ Objective-C มันจะทำให้การพัฒนาส่วนใหญ่ของคุณง่ายขึ้นจริง ๆ นั่นเป็นเหตุผลที่ Apple ใช้ความพยายามอย่างเต็มที่ในการสร้างมันตั้งแต่แรกและทำให้มันทำงานได้ดี

สำหรับกฎการจัดการหน่วยความจำเมื่อไม่ใช้ GC:

  • ถ้าคุณสร้างวัตถุใหม่โดยใช้+alloc/+allocWithZone:, +new, -copyหรือ-mutableCopyหรือถ้าคุณวัตถุคุณจะได้รับความเป็นเจ้าของของมันและต้องให้แน่ใจว่ามันจะถูกส่ง-retain-release
  • หากคุณได้รับวัตถุด้วยวิธีอื่นแสดงว่าคุณไม่ใช่เจ้าของและไม่ควรตรวจสอบว่ามีการส่ง-releaseวัตถุ
  • หากคุณต้องการให้แน่ใจว่าวัตถุจะถูกส่ง-releaseคุณสามารถส่งที่ตัวเองหรือคุณสามารถส่งวัตถุ-autoreleaseและปัจจุบันสระว่ายน้ำ autoreleaseจะส่ง-release(ครั้งต่อการได้รับ-autorelease) เมื่อสระว่ายน้ำเป็นเนื้อ

โดยทั่วไป-autoreleaseจะใช้เป็นวิธีการตรวจสอบให้แน่ใจว่าออบเจ็กต์อยู่ตามความยาวของเหตุการณ์ปัจจุบัน แต่จะถูกล้างข้อมูลในภายหลังเนื่องจากมีกลุ่มการปล่อยอัตโนมัติที่ล้อมรอบการประมวลผลเหตุการณ์ของ Cocoa ในโกโก้มันเป็นห่างไกลกันมากขึ้นที่จะกลับไปยังผู้โทรวัตถุที่ autoreleased กว่าก็คือการกลับมา objets โทรที่ตัวเองต้องการที่จะปล่อย


6

Objective-C ใช้Reference Countingซึ่งหมายความว่าแต่ละ Object จะมีจำนวนอ้างอิง เมื่อสร้างวัตถุขึ้นมาจะมีจำนวนอ้างอิงเป็น "1" พูดง่ายๆคือเมื่อมีการอ้างถึงวัตถุ (กล่าวคือเก็บไว้ที่ใดที่หนึ่ง) วัตถุนั้นจะถูก "คงไว้" ซึ่งหมายความว่าจำนวนการอ้างอิงจะเพิ่มขึ้นทีละหนึ่ง เมื่อไม่ต้องการวัตถุอีกต่อไปวัตถุนั้นจะถูก "ปล่อย" ซึ่งหมายความว่าจำนวนอ้างอิงจะลดลงทีละชิ้น

เมื่อจำนวนการอ้างอิงของวัตถุเป็น 0 วัตถุจะถูกปลดปล่อย นี่คือการนับอ้างอิงพื้นฐาน

สำหรับบางภาษาการอ้างอิงจะเพิ่มขึ้นและลดลงโดยอัตโนมัติ แต่ objective-c ไม่ใช่ภาษาเหล่านั้น ดังนั้นโปรแกรมเมอร์จึงต้องรับผิดชอบในการรักษาและปล่อย

วิธีทั่วไปในการเขียนวิธีการคือ:

id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;

ปัญหาในการจำปล่อยทรัพยากรที่ได้มาภายในโค้ดนั้นทั้งน่าเบื่อและเกิดข้อผิดพลาดได้ง่าย Objective-C นำเสนอแนวคิดอื่นที่มุ่งทำให้สิ่งนี้ง่ายขึ้น: Autorelease Pools Autorelease pool เป็นอ็อบเจ็กต์พิเศษที่ติดตั้งบนแต่ละเธรด เป็นคลาสที่ค่อนข้างเรียบง่ายหากคุณค้นหา NSAutoreleasePool

เมื่อออบเจ็กต์ได้รับข้อความ "autorelease" ที่ส่งถึงอ็อบเจ็กต์จะมองหากลุ่มการปล่อยอัตโนมัติใด ๆ ที่อยู่บนสแต็กสำหรับเธรดปัจจุบันนี้ มันจะเพิ่มออบเจ็กต์ลงในรายการเป็นอ็อบเจกต์เพื่อส่งข้อความ "รีลีส" ไปยังจุดใดจุดหนึ่งในอนาคตซึ่งโดยทั่วไปเมื่อพูลถูกปล่อยออกมา

เมื่อใช้รหัสด้านบนคุณสามารถเขียนใหม่ให้สั้นลงและอ่านง่ายขึ้นโดยพูดว่า:

id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;

เนื่องจากอ็อบเจ็กต์ถูกปล่อยออกมาโดยอัตโนมัติเราจึงไม่จำเป็นต้องเรียก "release" อย่างชัดเจนอีกต่อไป เนื่องจากเราทราบว่ากลุ่มการปล่อยอัตโนมัติบางส่วนจะดำเนินการให้เราในภายหลัง

หวังว่านี่จะช่วยได้ บทความ Wikipedia ค่อนข้างดีเกี่ยวกับการนับอ้างอิง ข้อมูลเพิ่มเติมเกี่ยวกับสระว่ายน้ำ autorelease สามารถพบได้ที่นี่ โปรดทราบว่าหากคุณกำลังสร้างสำหรับ Mac OS X 10.5 ขึ้นไปคุณสามารถบอกให้ Xcode สร้างโดยเปิดใช้งานการรวบรวมขยะซึ่งจะช่วยให้คุณละเว้นการเก็บ / รีลีส / การปล่อยอัตโนมัติได้โดยสิ้นเชิง


2
แค่นี้ก็ผิดแล้ว ไม่จำเป็นต้องส่ง someObject release หรือ autorlease ในตัวอย่างที่แสดง
mmalc

6

Joshua (# 6591) - สิ่งที่เก็บรวบรวมขยะใน Mac OS X 10.5 ดูเหมือนจะค่อนข้างดี แต่ไม่สามารถใช้ได้กับ iPhone (หรือหากคุณต้องการให้แอปของคุณทำงานบน Mac OS X เวอร์ชันก่อน 10.5)

นอกจากนี้หากคุณกำลังเขียนไลบรารีหรือสิ่งที่อาจนำมาใช้ซ้ำได้การใช้โหมด GC จะล็อกทุกคนที่ใช้รหัสเข้าสู่การใช้โหมด GC ด้วยดังนั้นตามที่ฉันเข้าใจใครก็ตามที่พยายามเขียนโค้ดที่ใช้ซ้ำได้มีแนวโน้มที่จะจัดการ หน่วยความจำด้วยตนเอง


2
เป็นไปได้อย่างสมบูรณ์แบบที่จะเขียนกรอบงานไฮบริดที่รองรับทั้ง GC และการนับอ้างอิง
mmalc

6

เช่นเคยเมื่อผู้คนเริ่มพยายามหาข้อมูลอ้างอิงซ้ำพวกเขามักจะได้รับสิ่งผิดปกติหรือให้คำอธิบายที่ไม่สมบูรณ์

แอปเปิ้ลให้คำอธิบายที่สมบูรณ์ของระบบการจัดการหน่วยความจำโกโก้ในการจัดการหน่วยความจำ Programming คู่มือสำหรับโกโก้ในตอนท้ายของการที่มีสั้น ๆ แต่สรุปที่ถูกต้องของกฎการจัดการหน่วยความจำ




2
อันที่จริงนี่เป็นบทสรุปหน้าเดียวที่ดีกว่ามาก: developer.apple.com/mac/library/documentation/Cocoa/Conceptual/…
Brian Moeskau

6

ฉันจะไม่เพิ่มการเก็บรักษา / รีลีสที่เฉพาะเจาะจงนอกเหนือจากที่คุณอาจต้องการคิดเกี่ยวกับการลดราคา $ 50 และรับหนังสือ Hillegass แต่ฉันขอแนะนำอย่างยิ่งให้ใช้เครื่องมือ Instruments ในช่วงต้นของการพัฒนาแอปพลิเคชันของคุณ (แม้แต่ของคุณ คนแรก!). โดยเรียกใช้ -> เริ่มต้นด้วยเครื่องมือประสิทธิภาพ ฉันจะเริ่มต้นด้วยการรั่วไหลซึ่งเป็นเพียงหนึ่งในเครื่องมือที่มีอยู่มากมาย แต่จะช่วยแสดงให้คุณเห็นเมื่อคุณลืมปล่อย เลิกกังวลว่าคุณจะนำเสนอข้อมูลมากแค่ไหน แต่ลองดูบทช่วยสอนนี้เพื่อลุกขึ้นและไปอย่างรวดเร็ว:
COCOA TUTORIAL: การแก้ไขการรั่วไหลของหน่วยความจำด้วยเครื่องมือ

การพยายามบังคับให้รั่วไหลอาจเป็นวิธีที่ดีกว่าในทางกลับกันเรียนรู้วิธีป้องกัน! โชคดี ;)


5

Matt Dillard เขียนว่า :

กลับ [[s autorelease] release];

การปล่อยอัตโนมัติไม่ได้เก็บรักษาวัตถุไว้ การปล่อยอัตโนมัติทำให้มันอยู่ในคิวเพื่อปล่อยในภายหลัง คุณไม่ต้องการให้มีแถลงการณ์การเปิดตัวที่นั่น




4

คำตอบของ NilObject คือการเริ่มต้นที่ดี ต่อไปนี้เป็นข้อมูลเพิ่มเติมเกี่ยวกับการจัดการหน่วยความจำด้วยตนเอง ( จำเป็นสำหรับ iPhone )

หากคุณalloc/initเป็นวัตถุเป็นการส่วนตัวมันมาพร้อมกับจำนวนอ้างอิง 1 คุณมีหน้าที่รับผิดชอบในการทำความสะอาดหลังจากนั้นเมื่อไม่มีความจำเป็นอีกต่อไปไม่ว่าจะโดยการโทร[foo release]หรือ[foo autorelease]หรือรีลีสจะล้างข้อมูลทันทีในขณะที่รีลีสอัตโนมัติจะเพิ่มอ็อบเจ็กต์ไปยังกลุ่มรีลีสอัตโนมัติซึ่งจะปล่อยโดยอัตโนมัติในภายหลัง

การปล่อยอัตโนมัติมีไว้สำหรับเมื่อคุณมีวิธีการที่ต้องการส่งคืนวัตถุที่เป็นปัญหา ( ดังนั้นคุณจึงไม่สามารถปล่อยได้ด้วยตนเองมิฉะนั้นคุณจะส่งคืนวัตถุศูนย์ ) แต่คุณไม่ต้องการยึดไว้เช่นกัน .

หากคุณได้รับวัตถุโดยที่คุณไม่ได้เรียกใช้การจัดสรร / เริ่มต้นเพื่อรับวัตถุ - ตัวอย่างเช่น:

foo = [NSString stringWithString:@"hello"];

แต่คุณต้องการที่จะเชื่อมต่อกับวัตถุนี้คุณต้องเรียกว่า [foo keep] มิฉะนั้นเป็นไปได้ที่จะได้รับautoreleasedและคุณจะยึดถือการอ้างอิงศูนย์(ตามที่แสดงในstringWithStringตัวอย่างด้านบน ) เมื่อคุณไม่ต้องการอีกต่อไปโทร[foo release].


2

คำตอบข้างต้นให้การอธิบายใหม่อย่างชัดเจนว่าเอกสารกล่าวถึงอะไร ปัญหาที่คนใหม่ ๆ ส่วนใหญ่พบคือกรณีที่ไม่มีเอกสาร ตัวอย่างเช่น:

  • Autorelease : docs บอกว่าจะทริกเกอร์การเปิดตัว "ณ จุดใดจุดหนึ่งในอนาคต" เมื่อไหร่?! โดยพื้นฐานแล้วคุณสามารถไว้วางใจวัตถุที่อยู่รอบ ๆ จนกว่าคุณจะออกจากรหัสของคุณกลับเข้าสู่ลูปเหตุการณ์ของระบบ ระบบอาจปล่อยวัตถุเมื่อใดก็ได้หลังจากรอบเหตุการณ์ปัจจุบัน (ฉันคิดว่า Matt พูดอย่างนั้นก่อนหน้านี้)

  • สตริงคงที่ : NSString *foo = @"bar";- คุณต้องเก็บหรือปล่อยสิ่งนั้นหรือไม่? ไม่แล้วล่ะ

    -(void)getBar {
        return @"bar";
    }

    ...

    NSString *foo = [self getBar]; // still no need to retain or release
  • กฎการสร้าง : หากคุณสร้างขึ้นแสดงว่าคุณเป็นเจ้าของและคาดว่าจะเผยแพร่

โดยทั่วไปแล้ววิธีที่โปรแกรมเมอร์ Cocoa คนใหม่ทำให้สับสนคือการไม่เข้าใจว่ากิจวัตรใดที่ส่งคืนวัตถุด้วยไฟล์retainCount > 0.

นี่คือตัวอย่างจากกฎง่ายๆสำหรับการจัดการหน่วยความจำในโกโก้ :

กฎการนับการเก็บรักษา

  • ภายในบล็อกที่กำหนดการใช้ -copy, -alloc และ -retain ควรเท่ากับการใช้ -release และ -autorelease
  • อ็อบเจ็กต์ที่สร้างขึ้นโดยใช้คอนสตรัคเตอร์อำนวยความสะดวก (เช่น stringWithString ของ NSString) ถือเป็นการปล่อยอัตโนมัติ
  • ใช้เมธอด -dealloc เพื่อปล่อยตัวแปรอินสแตนซ์ที่คุณเป็นเจ้าของ

สัญลักษณ์แสดงหัวข้อแรกบอกว่า: ถ้าคุณเรียกalloc(หรือnew fooCopy) คุณต้องเรียกรีลีสบนวัตถุนั้น

สัญลักษณ์แสดงหัวข้อย่อยที่ 2 ระบุว่า: หากคุณใช้ตัวสร้างความสะดวกและคุณต้องการให้วัตถุอยู่รอบ ๆ (เช่นเดียวกับภาพที่จะวาดในภายหลัง) คุณจะต้องคงไว้ (แล้วปล่อยในภายหลัง)

ข้อที่ 3 ควรอธิบายได้ด้วยตนเอง


"Autorelease: docs บอกว่าจะเริ่มการเปิดตัว" ในอนาคต "เมื่อไหร่?!" เอกสารมีความชัดเจนในประเด็นนั้น: "autorelease หมายถึง" ส่งข้อความเผยแพร่ในภายหลัง "(สำหรับคำจำกัดความบางประการในภายหลังโปรดดูที่" Autorelease Pools ")" อย่างมากเมื่อขึ้นอยู่กับกลุ่มพูลการปล่อยอัตโนมัติ ...
mmalc

... "ระบบอาจปล่อยวัตถุเมื่อใดก็ได้หลังจากรอบเหตุการณ์ปัจจุบัน" สิ่งนี้ทำให้ระบบเสียงค่อนข้างถูกกำหนดน้อยกว่าที่เป็นอยู่ ...
mmalc

... NSString foo = [getBar ตัวเอง]; // ยังไม่จำเป็นต้องเก็บหรือปล่อยนี่ไม่ถูกต้อง ใครก็ตามที่เรียกใช้ getBar ไม่ทราบรายละเอียดการใช้งานดังนั้น * ควรเก็บ / ปล่อย (โดยทั่วไปจะผ่านทาง accessors) หากต้องการใช้งานนอกขอบเขตปัจจุบัน
mmalc

บทความ "กฎที่เรียบง่ายมากสำหรับการจัดการหน่วยความจำในโกโก้" นั้นล้าสมัยไปหลายประการโดยเฉพาะ "ออบเจ็กต์ที่สร้างขึ้นโดยใช้ตัวสร้างความสะดวกสบาย (เช่น stringWithString ของ NSString) ถือเป็นการปล่อยอัตโนมัติ" ไม่ถูกต้อง - เป็นเพียง "ผู้รับไม่ได้เป็นเจ้าของ"
mmalc


0

ดังที่หลาย ๆ คนได้กล่าวไปแล้วIntro to Memory Managementของ Apple เป็นจุดเริ่มต้นที่ดีที่สุด

หนึ่งในการเชื่อมโยงที่มีประโยชน์ฉันไม่ได้เห็นกล่าวถึงเลยคือการปฏิบัติจัดการหน่วยความจำ คุณจะพบมันอยู่ตรงกลางเอกสารของ Apple หากคุณอ่านทั้งหมด แต่ควรเชื่อมโยงโดยตรง เป็นบทสรุปสำหรับผู้บริหารที่ยอดเยี่ยมเกี่ยวกับกฎการจัดการหน่วยความจำพร้อมตัวอย่างและข้อผิดพลาดทั่วไป (โดยทั่วไปแล้วคำตอบอื่น ๆ ที่พยายามอธิบายในที่นี้ แต่ก็ไม่ดีเช่นกัน)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.