ทำไม @autoreleasepool ยังต้องการ ARC อยู่


191

ส่วนใหญ่ด้วย ARC (การอ้างอิงโดยอัตโนมัติ) เราไม่จำเป็นต้องคิดถึงการจัดการหน่วยความจำเลยด้วย Objective-C ไม่อนุญาตให้สร้างNSAutoreleasePoolอีกต่อไปอย่างไรก็ตามมีไวยากรณ์ใหม่:

@autoreleasepool {
    
}

คำถามของฉันคือทำไมฉันจะต้องใช้สิ่งนี้เมื่อฉันไม่ควรปล่อย / ตอบรับอัตโนมัติด้วยตนเอง


แก้ไข:เพื่อสรุปสิ่งที่ฉันได้จากคำตอบและความคิดเห็นทั้งหมด:

ไวยากรณ์ใหม่:

@autoreleasepool { … } เป็นไวยากรณ์ใหม่สำหรับ

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

[pool drain];

ที่สำคัญกว่า:

  • ใช้ ARC เช่นเดียวกับautoreleaserelease
  • มันต้องการพูลการปล่อยอัตโนมัติในสถานที่
  • ARC ไม่ได้สร้างกลุ่มการปล่อยอัตโนมัติให้คุณ อย่างไรก็ตาม:
    • เธรดหลักของแอป Cocoa ทุกแอปมีพูลการเลิกอัตโนมัติอยู่แล้ว
  • มีสองโอกาสที่คุณอาจต้องการใช้ประโยชน์จาก@autoreleasepool:
    1. myRunLoop(…) { @autoreleasepool { … } return success; }เมื่อคุณอยู่ในหัวข้อรองและไม่มีสระว่ายน้ำเปิดตัวรถยนต์คุณต้องทำด้วยตัวเองเพื่อป้องกันการรั่วไหลเช่น
    2. เมื่อคุณต้องการสร้างสระว่ายน้ำในท้องถิ่นมากขึ้นตามที่ @mattjgalloway ได้แสดงไว้ในคำตอบของเขา

1
นอกจากนี้ยังมีโอกาสที่สาม: เมื่อคุณพัฒนาบางสิ่งที่ไม่เกี่ยวข้องกับ UIKit หรือ NSFoundation สิ่งที่ใช้เครื่องมือบรรทัดคำสั่งหรือดังนั้น
Garnik

คำตอบ:


215

ARC ไม่ได้กำจัดการเปิดตัวและการเผยแพร่อัตโนมัติเพียงเพิ่มสิ่งที่จำเป็นสำหรับคุณ ดังนั้นยังคงมีสายที่จะเก็บไว้ยังคงมีสายที่จะปล่อยยังคงมีการโทรไปที่การยกเลิกอัตโนมัติและยังคงมีพูลการปล่อยอัตโนมัติ

หนึ่งในการเปลี่ยนแปลงอื่น ๆ ที่พวกเขาทำกับคอมไพเลอร์ Clang 3.0 ใหม่และ ARC คือพวกเขาแทนที่NSAutoReleasePoolด้วย@autoreleasepoolคอมไพเลอร์คำสั่ง NSAutoReleasePoolยังเป็น "วัตถุ" พิเศษอยู่เสมอและพวกเขาก็สร้างมันขึ้นมาเพื่อให้รูปแบบการใช้งานนั้นไม่สับสนกับวัตถุดังนั้นโดยทั่วไปแล้วจะง่ายกว่าเล็กน้อย

โดยพื้นฐานแล้วคุณต้องการ@autoreleasepoolเพราะยังมีกลุ่มการปล่อยอัตโนมัติที่ต้องกังวล คุณไม่ต้องกังวลเกี่ยวกับการเพิ่มautoreleaseสาย

ตัวอย่างของการใช้พูลรีลีสอัตโนมัติ:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

ตัวอย่างที่วางแผนไว้อย่างมหาศาลแน่นอน แต่ถ้าคุณไม่มี@autoreleasepoolด้านในfor-loop ด้านนอกคุณจะต้องปล่อยวัตถุ 100000000 ในภายหลังแทนที่จะเป็น 10,000 ในแต่ละครั้งที่รอบนอกfor-loop

อัปเดต: ดูคำตอบนี้ด้วย - https://stackoverflow.com/a/7950636/1068248 - เพราะเหตุ@autoreleasepoolใด ARC จึงไม่เกี่ยวข้องกับสิ่งใด

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


11
มันไม่ได้กำจัดการเก็บรักษา มันเพิ่มไว้ในสำหรับคุณ การนับการอ้างอิงยังคงดำเนินต่อไปมันเป็นเพียงอัตโนมัติ ดังนั้นการนับการอ้างอิงอัตโนมัติ :-D
mattjgalloway

6
ดังนั้นทำไมมันไม่เพิ่มใน@autoreleasepoolสำหรับฉันด้วยหรือไม่ หากฉันไม่ได้ควบคุมสิ่งที่ได้รับ autoreleased หรือปล่อยออกมา (ARC ทำเช่นนั้นสำหรับฉัน) ฉันจะทราบได้อย่างไรว่าจะตั้งค่าพูล autorelease เมื่อใด
mk12

5
แต่คุณสามารถควบคุมตำแหน่งที่พูลรีลีสอัตโนมัติของคุณยังคงอยู่ โดยค่าเริ่มต้นจะมีหนึ่งพันรอบแอปทั้งหมดของคุณ แต่คุณอาจต้องการมากกว่านี้
mattjgalloway

5
คำถามที่ดี. คุณเพียงแค่ต้อง "รู้" คิดว่าการเพิ่มสิ่งหนึ่งคล้ายกับเหตุผลว่าทำไมในภาษา GC อาจเพิ่มคำใบ้ลงในตัวรวบรวมขยะเพื่อดำเนินการต่อและเรียกใช้วงจรการรวบรวมในตอนนี้ บางทีคุณอาจรู้ว่ามีวัตถุจำนวนมากพร้อมที่จะถูกล้างออกคุณมีลูปที่จัดสรรวัตถุเทมเพลตจำนวนมากดังนั้นคุณจะ "รู้" (หรือเครื่องมืออาจบอกคุณ :) ว่าการเพิ่มพูลการปล่อยรอบลูปจะเป็น ความคิดที่ดี.
Graham Perks

6
ตัวอย่างการวนซ้ำทำงานได้อย่างสมบูรณ์แบบโดยไม่ต้องยกเลิกการทำงานอัตโนมัติ: แต่ละวัตถุจะถูกจัดสรรคืนเมื่อตัวแปรไม่อยู่ในขอบเขต การรันโค้ดโดยไม่มีการบันทึกอัตโนมัติจะใช้จำนวนหน่วยความจำคงที่และแสดงให้เห็นพอยน์เตอร์ที่ถูกนำมาใช้ซ้ำและวางเบรกพอยต์บน dealloc ของวัตถุแสดงว่ามันถูกเรียกครั้งละครั้งผ่านลูปเมื่อ objc_storeStrong บางที OSX อาจทำอะไรบางอย่างที่โง่เง่า แต่ autoreleasepool ไม่จำเป็นอย่างสมบูรณ์ใน iOS
Glenn Maynard

16

@autoreleasepoolไม่ได้หยุดการทำงานอัตโนมัติอีกต่อไป มันสร้างพูลอัตโนมัติที่มีการปลดล็อกอัตโนมัติดังนั้นเมื่อถึงจุดสิ้นสุดของบล็อกวัตถุใด ๆ ที่ถูก autorelosed โดย ARC ในขณะที่บล็อกนั้นเปิดใช้งานอยู่จะถูกส่งข้อความการปล่อย คู่มือการเขียนโปรแกรมการจัดการหน่วยความจำขั้นสูงของ Apple อธิบายดังนี้:

ในตอนท้ายของบล็อกพูล autorelease วัตถุที่ได้รับข้อความ autorelease ภายในบล็อกจะถูกส่งข้อความ release - วัตถุจะได้รับข้อความ release สำหรับแต่ละครั้งที่มีการส่งข้อความ autorelease ภายในบล็อก


1
ไม่จำเป็น. วัตถุจะได้รับreleaseข้อความ แต่หากจำนวนการเก็บรักษาคือ> 1 วัตถุจะไม่ถูกจัดสรรคืน
andybons

@andybons: อัปเดต; ขอบคุณ นี่เป็นการเปลี่ยนแปลงจากพฤติกรรมก่อน ARC หรือไม่
outis

สิ่งนี้ไม่ถูกต้อง วัตถุที่ออกโดย ARC จะถูกส่งข้อความเผยแพร่ทันทีที่ ARC เผยแพร่โดยมีหรือไม่มีพูลการกู้คืนอัตโนมัติ
Glenn Maynard

7

ผู้คนมักเข้าใจผิดว่า ARC สำหรับการเก็บขยะบางประเภทหรือที่คล้ายกัน ความจริงก็คือว่าหลังจากที่บางคนเวลาที่แอปเปิ้ล (ขอบคุณ LLVM และโครงการเสียงดังกราว) ตระหนักว่าการบริหารจัดการหน่วยความจำวัตถุประสงค์-C (ทั้งหมดretainsและreleasesอื่น ๆ ) สามารถ automatized อย่างเต็มที่ที่รวบรวมเวลา นี่คือเพียงแค่อ่านรหัสก่อนที่จะรัน :)

ในการทำเช่นนั้นมีเพียงเงื่อนไขเดียวเท่านั้น: เราต้องปฏิบัติตามกฎมิฉะนั้นผู้รวบรวมจะไม่สามารถดำเนินการอัตโนมัติในเวลารวบรวม ดังนั้นเพื่อให้แน่ใจว่าเราไม่เคยทำลายกฎที่เราไม่ได้รับอนุญาตอย่างชัดเจนเขียนrelease, retainฯลฯ โทรเหล่านั้นจะถูกฉีดโดยอัตโนมัติเป็นรหัสของเราโดยการคอมไพเลอร์ ดังนั้นภายในเรายังคงมีautoreleases, retain, releaseฯลฯ มันเป็นเพียงการที่เราไม่จำเป็นต้องเขียนพวกเขาอีกต่อไป

A of ARC เป็นไปโดยอัตโนมัติในเวลารวบรวมซึ่งดีกว่ามากในเวลาทำงานเช่นการรวบรวมขยะ

เรายังมี@autoreleasepool{...}เพราะมันไม่ได้ผิดกฎใด ๆ เราเป็นอิสระในการสร้าง / ระบายสระว่ายน้ำของเราเมื่อใดก็ตามที่เราต้องการ :)


1
ARC คือการอ้างอิงการนับ GC ไม่ใช่การทำเครื่องหมายและกวาดอย่าง GC อย่างที่คุณได้รับใน JavaScript และ Java แต่เป็นการรวบรวมขยะแน่นอน สิ่งนี้ไม่ได้ตอบคำถาม - "คุณทำได้" ไม่ตอบคำถาม "ทำไมคุณควร" คุณไม่ควร
Glenn Maynard

3

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


คุณช่วยยกตัวอย่างให้ฉันฟังได้ไหมว่าคุณจะต้องทำเมื่อไหร่?
mk12


ตัวอย่างเช่นก่อน ARC ฉันมี CVDisplayLink ทำงานอยู่ในเธรดรองสำหรับแอป OpenGL ของฉัน แต่ฉันไม่ได้สร้างพูลอัตโนมัติใน runloop เพราะฉันรู้ว่าฉันไม่ได้ทำการขายอัตโนมัติ (หรือใช้ไลบรารีที่ทำ) นั่นหมายความว่าตอนนี้ฉันต้องเพิ่ม@autoreleasepoolเพราะฉันไม่รู้ว่า ARC อาจตัดสินใจยกเลิกการปิดกั้นอัตโนมัติหรือไม่
mk12

@ Mk12 - ไม่คุณจะยังคงมีพูลการปล่อยอัตโนมัติที่ถูกระบายทุกครั้งที่วิ่งวนรอบหลัก คุณควรเพิ่มเมื่อคุณต้องการให้แน่ใจว่าวัตถุที่ถูกลบออกอัตโนมัติได้รับการระบายออกก่อนที่พวกเขาจะเป็นอย่างอื่น - ตัวอย่างเช่นในครั้งต่อไปรอบวนรอบการทำงาน
mattjgalloway

2
@DougW - ฉันดูว่าคอมไพเลอร์ทำอะไรและบล็อกเกี่ยวกับมันที่นี่ - iphone.galloway.me.uk/2012/02/a-look-under-arcs-hood- –-episode-3 / หวังว่าจะอธิบายสิ่งที่เกิดขึ้นทั้งในเวลารวบรวมและเวลาทำงาน
mattjgalloway

2

อ้างถึงจากhttps://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html :

Autorelease Pool Blocks และ Threads

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

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

หมายเหตุ: ถ้าคุณสร้างเธรดรองโดยใช้ POSIX เธรด APIs แทน NSThread คุณจะไม่สามารถใช้ Cocoa เว้นแต่ว่า Cocoa อยู่ในโหมดมัลติเธรด Cocoa เข้าสู่โหมดมัลติเธรดหลังจากแยกวัตถุ NSThread แรกเท่านั้น ในการใช้ Cocoa บนเธรด POSIX สำรองแอปพลิเคชันของคุณจะต้องแยกวัตถุ NSThread อย่างน้อยหนึ่งอันออกซึ่งสามารถออกได้ทันที คุณสามารถทดสอบว่า Cocoa อยู่ในโหมดมัลติเธรดหรือไม่ด้วยเมธอดคลาส NSThread isMultiThreaded

...

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


2

พูลการกู้คืนอัตโนมัติจำเป็นต้องมีเพื่อส่งคืนวัตถุที่สร้างขึ้นใหม่จากวิธีการ เช่นพิจารณารหัสชิ้นนี้:

- (NSString *)messageOfTheDay {
    return [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
}

สตริงที่สร้างขึ้นในวิธีการจะมีจำนวนการเก็บรักษาไว้หนึ่ง ตอนนี้ใครจะเป็นคนที่รักษาสมดุลที่นับด้วยการเปิดตัว?

วิธีการของตัวเอง? เป็นไปไม่ได้มันจะต้องส่งคืนวัตถุที่สร้างขึ้นดังนั้นจึงต้องไม่ปล่อยมันก่อนที่จะส่งคืน

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

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

นั่นเป็นเหตุผลที่มีพูลการถอนการปิดอัตโนมัติดังนั้นวิธีการแรกจะกลายเป็นจริง

- (NSString *)messageOfTheDay {
    NSString * res = [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
    return [res autorelease];
}

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

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

พิจารณารหัส ARC นี้:

// Callee
- (SomeObject *)getSomeObject {
    return [[SomeObject alloc] init];
}

// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];

รหัสที่ระบบสร้างสามารถทำงานได้เหมือนรหัสต่อไปนี้ (ซึ่งเป็นรุ่นที่ปลอดภัยที่ช่วยให้คุณสามารถผสมรหัส ARC และรหัสที่ไม่ใช่ ARC ได้อย่างอิสระ):

// Callee
- (SomeObject *)getSomeObject {
    return [[[SomeObject alloc] init] autorelease];
}

// Caller
SomeObject * obj = [[self getSomeObject] retain];
[obj doStuff];
[obj release];

(โปรดทราบว่าการเก็บรักษา / การปล่อยในผู้โทรเป็นเพียงการรักษาความปลอดภัยการป้องกันมันไม่จำเป็นต้องเคร่งครัดรหัสจะถูกต้องสมบูรณ์แบบโดยไม่มีมัน)

หรือมันสามารถทำตัวเหมือนรหัสนี้ในกรณีที่ตรวจพบว่าทั้งคู่ใช้ ARC ในขณะใช้งานจริง:

// Callee
- (SomeObject *)getSomeObject {
    return [[SomeObject alloc] init];
}

// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
[obj release];

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

ตอนนี้คำถามที่เกิดขึ้นจริง: ทำไมหนึ่งจะใช้@autoreleasepool?

สำหรับนักพัฒนาส่วนใหญ่มีเพียงเหตุผลเดียวที่เหลืออยู่วันนี้สำหรับการใช้งานโครงสร้างนี้ในรหัสของพวกเขา เช่นพิจารณาลูปนี้:

for (int i = 0; i < 1000000; i++) {
    // ... code ...
    TempObject * to = [TempObject tempObjectForData:...];
    // ... do something with to ...
}

สมมติว่าทุกการเรียกไปยังtempObjectForDataอาจสร้างใหม่TempObjectที่ส่งคืนอัตโนมัติ for-loop จะสร้างหนึ่งล้านของวัตถุ temp เหล่านี้ซึ่งถูกรวบรวมทั้งหมดใน autoreleasepool ปัจจุบันและเพียงครั้งเดียวที่สระว่ายน้ำถูกทำลายวัตถุ temp ทั้งหมดจะถูกทำลายเช่นกัน คุณจะมีวัตถุชั่วคราวหนึ่งล้านในหน่วยความจำ

หากคุณเขียนรหัสเช่นนี้แทน:

for (int i = 0; i < 1000000; i++) @autoreleasepool {
    // ... code ...
    TempObject * to = [TempObject tempObjectForData:...];
    // ... do something with to ...
}

จากนั้นมีการสร้างพูลใหม่ทุกครั้งที่ for-loop ทำงานและถูกทำลายเมื่อสิ้นสุดการวนซ้ำแต่ละครั้ง ด้วยวิธีนี้วัตถุ temp ส่วนใหญ่นั้นจะวนอยู่ในหน่วยความจำตลอดเวลาแม้จะมีลูปที่ทำงานหนึ่งล้านครั้งก็ตาม

ในอดีตคุณจะต้องจัดการ autoreleasepools ด้วยตนเองเมื่อจัดการกับเธรด (เช่นการใช้NSThread) เนื่องจากเฉพาะเธรดหลักเท่านั้นที่มีพูล autorelease โดยอัตโนมัติสำหรับแอพ Cocoa / UIKit แต่นี่เป็นมรดกที่ค่อนข้างมากในวันนี้เพราะวันนี้คุณอาจจะไม่ใช้กระทู้เริ่มต้น คุณจะใช้ GCD DispatchQueueหรือNSOperationQueueทั้งสองอย่างนี้จัดการกับกลุ่มการ autorelease ระดับบนให้คุณสร้างขึ้นก่อนที่จะรันบล็อก / งานและทำลายเมื่อทำเสร็จแล้ว


-4

ดูเหมือนจะมีความสับสนมากในหัวข้อนี้ (และอย่างน้อย 80 คนที่อาจสับสนในตอนนี้และคิดว่าพวกเขาต้องโรย @autoreleasepool รอบ ๆ รหัสของพวกเขา)

หากโปรเจ็กต์ (รวมถึงการขึ้นต่อกัน) ใช้ ARC เพียงอย่างเดียวดังนั้น @autoreleasepool ไม่จำเป็นต้องใช้และจะไม่ทำสิ่งใดมีประโยชน์ ARC จะจัดการกับการปล่อยวัตถุในเวลาที่ถูกต้อง ตัวอย่างเช่น:

@interface Testing: NSObject
+ (void) test;
@end

@implementation Testing
- (void) dealloc { NSLog(@"dealloc"); }

+ (void) test
{
    while(true) NSLog(@"p = %p", [Testing new]);
}
@end

แสดง:

p = 0x17696f80
dealloc
p = 0x17570a90
dealloc

การทดสอบวัตถุแต่ละชิ้นจะถูกจัดสรรคืนทันทีที่ค่าไม่อยู่ในขอบเขตโดยไม่ต้องรอให้มีการออกจากระบบ autorelease โดยอัตโนมัติ (สิ่งเดียวกันเกิดขึ้นกับตัวอย่างของ NSNumber สิ่งนี้ช่วยให้เราสังเกตการณ์ dealloc) ARC ไม่ได้ใช้การยกเลิกอัตโนมัติ

เหตุผลที่ @autoreleasepool ยังคงใช้ได้สำหรับโครงการ ARC แบบผสมและไม่ใช่ ARC ซึ่งยังไม่ได้เปลี่ยนเป็น ARC อย่างสมบูรณ์

หากคุณโทรเข้าไปในรหัสที่ไม่ใช่ ARC มันอาจกลับมาเป็นวัตถุอัตโนมัติ ในกรณีดังกล่าวลูปด้านบนจะรั่วไหลเนื่องจากพูลการ autorelease ปัจจุบันจะไม่ออก นั่นคือสิ่งที่คุณต้องการวาง @autoreleasepool รอบ ๆ บล็อครหัส

แต่ถ้าคุณได้ทำการเปลี่ยนแปลง ARC อย่างสมบูรณ์แล้วลืมเกี่ยวกับ autoreleasepool


4
คำตอบนี้ผิดและยังขัดกับเอกสารของ ARC หลักฐานของคุณมีความสำคัญเพราะคุณใช้วิธีการจัดสรรที่คอมไพเลอร์ตัดสินใจที่จะไม่หยุดการทำงานอัตโนมัติ คุณสามารถดูสิ่งนี้ไม่ทำงานหากคุณสร้าง initializer แบบคงที่ใหม่สำหรับคลาสที่คุณกำหนดเอง สร้างเครื่องมือเริ่มต้นนี้และใช้ในลูปของคุณ: + (Testing *) testing { return [Testing new] }. จากนั้นคุณจะเห็นว่า dealloc จะไม่ถูกเรียกจนกระทั่งในภายหลัง สิ่งนี้จะได้รับการแก้ไขถ้าคุณหุ้มด้านในของวงใน@autoreleasepoolบล็อก
Dima

@Dima ใช้งานบน iOS10 แล้วจะได้รับการเรียกคืนทันทีหลังจากพิมพ์ที่อยู่ของวัตถุ + (Testing *) testing { return [Testing new];} + (void) test { while(true) NSLog(@"p = %p", [self testing]);}
KudoCC

@ KudoCC - ฉันก็เช่นกันและฉันก็เห็นพฤติกรรมแบบเดียวกับที่คุณทำ แต่เมื่อฉัน[UIImage imageWithData]เข้าสู่สมการจากนั้นในทันใดฉันก็เริ่มเห็นautoreleaseพฤติกรรมดั้งเดิมที่ต้อง@autoreleasepoolรักษาความทรงจำสูงสุดในระดับที่เหมาะสม
Rob

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