ARC (Automatic Reference Counting) Part I

ตุลาคม 15, 2011 at 1:31 am 4 ของความคิดเห็น

สิ้นสุด NDA เกี่ยวกับ iOS SDK ซักที หลังจากนี้ คงมี Entry ใหม่ๆให้เขียนเยอะแยะเลยทีเดียว เรื่องที่จะคุยกันใน Entry นี้เป็นเรื่องทีเด็ดของ Objective-C เลยก็ว่าได้ คือเรื่องของ ARC ใน Entry มาทำความรู้จักกันพอสังเขปก่อนดีกว่า

ARC ย่อมาจาก Automatic Reference Counting ดังที่ทราบกันอยู่แล้วว่าการจัดการ Memory ใน Objective-C นั้น ใช้การนับ (Counting) การอ้างอิงถึง (Reference) ตัวแปรนั้นๆ ว่ายังสมควรจะอยู่ใน Memory อยู่มั้ย? ซึ่งก่อนหน้านี้เราต้องเป็นคนจัดการเอง(นับเอง เพิ่มเอง ลบเอง) แต่ด้วย ARC มันก็ทำให้เราโดยอัตโนมัติ เท่านั้นเอง คอนเซปต์ง่ายๆแค่นี้

ช่วงต้นปีที่ Xcode4 ออกมาใหม่ๆ มีการแนะนำ Compiler ตัวใหม่ชื่อว่า “LLVM” ซึ่งมีประสิทธิภาพและความสามารถสูงกว่า Compiler ตัวเก่า “GCC” อย่างมากมาย ทั้งความเร็ว, Error Message ที่ Programmer friendly มากกว่า, ฯลฯ ในช่วงแนะนำมีการนำเสนอหนึ่งในฟีเจอร์ของ LLVM เป็น Analyzer ที่ชื่อว่า Clang ผลการทำงานน่าประทับใจมาก สามารถแสดงผลทีละสเต็ปได้เลยว่า ตรงไหนจะ leak เริ่มจากไหนและจบตรงไหน แต่เคยสงสัยบ้างรึเปล่าว่า “ถ้าเก่งซะขนาดนี้ แล้วทำไมไม่แก้ให้ด้วยล่ะ” …นี่แหละครับ ที่มาของ ARC

ผมขอเปรียบให้ ARC เป็นเหมือนช่างซ่อมรถมือโปรมองรถคุณปราดเดียวรู้เลยว่า “ตรงนี้เครื่องหลวมนะ ตรงนั้นต้องซ่อมนะ” ถ้าเป็นรถคุณ คุณก็คงบอกว่า “งั้นพี่ซ่อมให้ผมไปเลยก็แล้วกัน” แต่ ARC กลับตอบกลับว่า “ไม่ได้เอาเครื่องมือมา ลูกมือก็ไม่มี” …นี่เป็นคำตอบของคำถามข้างบนครับ ว่าทำไม ARC ไม่แก้ให้เราไปซะเลย

…แม้ว่า ARC จะขึ้นต้นด้วยคำว่า Automatic แต่ก็ไม่ได้หมายความว่า “เราไม่ต้องทำอะไรเลย” เราก็ยังควรรู้การ Programming เพื่อให้เข้ากับการทำงานของ ARC ได้อย่างเต็มที่เช่นกัน จากตัวอย่างข้างต้น ถ้า ARC กำลังซ่อมรถให้เราแต่เรามีแต่เครื่องมือมาตรฐาน ไขควงอันเดียว ประแจซักสามสี่เบอร์เท่าที่พอใช้ได้ การซ่อมรถของ ARC ก็คงได้ผลเท่าที่เครื่องมือพอจะอำนวยให้ได้

การมีอยู่ของ ARC ทำให้หน้าที่ของเราเปลี่ยนไป “เราไม่ต้องระวังเรื่อง Memory Leak อีกต่อไป แต่การ Optimize ยังคงเป็นหน้าที่ของเราอยู่”

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

แต่ถ้าคุณใช้ ARC Programming ก็เปรียบเสมือน คุณอาจมีการวัด BMA ของแฟนคุณ ดูกรุ๊ปเลือดว่าควรกินอะไรไม่ควรกินอะไร ลักษณะร่างกาย ฯลฯ และออกแบบเมนูสำหรับเขาโดยเฉพาะเลย ผลก็คือ แฟนคุณก็จะมีหุ่นสวยเป็น S Shape ไปเลยก็ว่าได้ (ตัวอย่างก็ประมาณนี้ เรื่องจริงจะเป็นไง ผมไม่รู้นะครับ ฮาๆๆ)

คำถามต่อมาก็คือ แล้วมันต่างจาก Garbage Collector (GC) ยังไง : ความแตกต่างก็คือ ARC ทำงานในช่วง Compile Time ในขณะที่ GC ทำในช่วง Runtime อย่างที่บอกว่า ARC เข้ามาเสริมในขั้นตอนของการ Analyze ให้แก้ได้ด้วย ดังนั้น สิ่งที่ ARC ทำก็คล้ายๆกับการเติม Retain/Release/Autorelease ในโค้ดให้เราตามที่มันเห็นสมควรเท่านั้นเอง (แม้ว่าจริงๆจะไม่ใช้แบบนั้นซะทีเดียว แต่ก็พอจะเข้าใจแบบนั้นได้) จากนั้นก็ทำงานไปตามปกติ ต่างจาก GC ที่ไล่เช็คตัวแปรในโปรแกรมไปเป็นช่วงๆว่าอันไหนใช้อยู่ อันไหนไม่ใช้ แล้วก็ค่อยเคลียร์ไปเป็นรอบๆไป

เราจะเริ่มต้น ARC ได้อย่างไร? : สิ่งแรกที่เราต้องเปลี่ยนคือ “แนวคิด” ในการจัดการตัวแปร จากเมื่อก่อนเราคิดตามกฎง่ายๆว่า “alloc/retain เอง ก็ release ด้วย” และ “ถ้าไม่ได้ alloc/release เองก็ไม่ต้องทำอะไร” ตอนนี้เราต้องเปลี่ยนเป็น “อะไรสำคัญให้ strong นอกจากนั้นว่ากันอีกที” แล้วครับ

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

จากที่กล่าวไปข้างต้น คิดว่าคงพอจะเห็นภาพรวมกว้างๆ และความจำเป็นของ ARC กันบ้างแล้ว คราวนี้มาดูการใช้งานกันคร่าวๆ

Property Type ของ ARC หลักๆ ก็มีใช้อยู่ 4 แบบ คือ __strong, __weak, __unsafe_unretain และ __autoreleasing แต่ละตัวเป็นการกำหนดลักษณะของ ตัวแปรแต่ละอย่าง

  • __strong คือ ตัวแปรนั้นต้องมีการเก็บค่าเอาไว้ตลอดเวลา จะใช้ตอนไหนต้องเรียกได้ เพราะว่า “สำคัญ” นั่นเอง
  • __weak หมายถึงตัวแปรนั้นพร้อมที่จะมีการ release อยู่ตลอดเวลา (Zeroing) และค่าในตัวแปรนั้นก็พร้อมจะเป็น nil ตลอดเวลาเช่นกัน
  • __unsafe_unretain คล้ายๆกับ weak ต่างกันตรงที่ตัวแปรนั้นจะไม่พร้อม release (Non-Zeroing)
  • __autoreleasing คล้ายๆกับ autorelease แบบเก่า ตัวแปรจะเก็บลงใน autorelease pool เพื่อรอการ release แต่โดยปกติแล้วไม่ค่อยใช้

การใช้งานโดยปกติแล้ว ถ้าไม่ระบุอะไรเลย จะเป็นการกำหนดว่าใช้ strong โดย default ถ้าเราไม่กำหนดอะไรเลย เท่ากับว่าตัวแปรทุกตัวใน app เราก็จะเป็น strong ทั้งหมด ทั้งแอพเราก็จะบริโภค memory ตามที่ต้องการ ถ้าเปรียบเทียบกับหุ่นแฟนก็เป็นหุ่นมาตรฐานตามที่ยกมาก่อนหน้านี้นั่นเอง

การกำหนด Property ให้กับตัวแปร ก็ไม่มีอะไรมาก เปลี่ยนจากที่เคยกำหนดว่าเป็น retain, copy, assign มาเป็น strong หรือ weak เท่านั้นเอง ส่วนจะเป็นค่าไหน ก็ตามที่บอกจากส่วนแนวคิด อะไรสำคัญหายไม่ได้ก็ strong อันไหนไม่สำคัญหรือมีการเปลี่ยนแปลงหรือเป็น nil ได้ ก็ weak แค่นี้เอง syntax สำหรับ class instance ก็จะลักษณะนี้

@interface Class : UIViewController
@property (strong, nonatomic) NSArray *essentialDatasource;
@end

ส่วน local function จะเป็นแบบนี้

__strong NSString *requiredParameter = @"&id=1234";
__weak NSString *optionParameter = @"&format=xml";
MyClass *isStrongByDefault = [[MyClass alloc] init];

จากตัวอย่างข้างต้นนะครับ ลักษณะก็จะประมาณนี้ ไม่ต้องมีการ retain, release หรือ autorelease ใดๆทั้งสิ้น จะ alloc ก็ alloc ไปครับ เพราะ ARC  จะไปหาที่ release ที่เหมาะสมให้กับเราเอง สิ่งที่เราต้อง focus ก็คือตรงไหนสำคัญไม่สำคัญมากกว่า …เท่านี้เองครับ

สำหรับ โปรเจคเก่าๆ Xcode ก็มีเครื่องมือในการ Covert ไปเป็น ARC อยู่ใน Edit->Refactor->Convert to ARC อยู่แล้ว ถ้าครั้งแรกยังไม่ผ่านก็ไม่ต้องตกใจครับ แก้ไขไปเรื่อยๆตามที่ Error ขึ้น ส่วนมากก็แค่ให้ลบที่เราเคย release, autorelease ไว้เท่านั้น แถมถ้าแก้ไม่ถูก ยังมี fix-it ให้ใช้อีกตะหาก …แทบไม่ต้องทำอะไรแล้วเนี่ย

สำหรับ Entry นี้ ขอเบรคไว้เท่านี้ก่อน ส่วนรายละเอียดอื่นๆ เช่น รายละเอียดเกี่ยวกับ Type weak, การ Bridge ค่า ฯลฯ ที่จะเป็นการลงลึกมากกว่านี้ ไว้ว่ากันใน Entry หน้าครับ Happy Coding with ARC ครับ :)

อ่านต่อเนื้อหาได้ที่

Part II : https://onoaonoa.wordpress.com/2011/11/12/arc-automatic-reference-counting-part-ii/

Entry filed under: Cocoa Programming, Computer, iPhone Programming.

Objective-C Coding Style : Naming Movie : Top Secret วัยรุ่นพันล้าน

4 ความเห็น Add your own

  • 1. memogames  |  ตุลาคม 29, 2011 เวลา 3:15 pm

    ขอบคุณสำหรับข้อมูล เป็น entry ที่มีประโยชน์มากๆ ครับ ขอถามคำถามเพิ่มเติมและเผื่อสำหรับคนอื่นที่เข้ามาอ่านด้วย อย่างที่รู้กันถ้าเราสร้างโปรเจคจาก Xcode 4.2 (iOS SDK 5) จะมี ARC เข้ามาเรียบร้อยแล้ว สังเกตุได้ง่ายๆ คือจะมีพวก strong เหมือนใน entry ข้างบน และฟังชันก์ dealloc จะหายไปใน class พวก UIViewController ในขณะเดียวกันเมื่อเราสร้างโปรเจคจาก Xcode 4.1.x ลงมา (iOS SDK 4.x) ก็จะยังไม่มี ARC ซึ่งแน่นอนเราก็ยังคงจะต้องจัดการเกี่ยวกับ memory กันอยู่ คำถามผมคือ ถ้าผมเริ่มสร้างโปรเจคจาก Xcode 4.2 ที่มี ARC แล้วนำโปรแกรมที่ได้ไปรันบน iOS ที่ต่ำกว่า 5.0 ตัว Compiler จะจัดการ Memory ให้อัตโนมัติได้หรือไม่ หรือจะสามารถใช้ได้เฉพาะบน iOS5 ขึ้นไปเท่านั้น

    ขอบคุณครับ

    ปล. ผมเคยถามคำถามนี้ไปแล้ว แต่จำไม่ค่อยได้เท่าไร มาขอทวนความจำ และเผื่อคนอื่นที่เข้ามาอ่าน entry นี้จะได้เห็นด้วย ^^

    ตอบกลับ
    • 2. Jerapong Nampetch  |  ตุลาคม 30, 2011 เวลา 2:05 am

      ARC Support iOS ตั้งแต่เวอร์ชั่น 4 ขึ้นไปครับ ดังนั้น ARC ยังคงทำงานได้ครับ :)

      ตอบกลับ
  • 3. mossila  |  พฤศจิกายน 4, 2011 เวลา 3:59 pm

    เยี่ยมเลยครับ รอ part 2 นะครับ

    ตอบกลับ
  • 4. ARC (Automatic Reference Counting) Part II « OnoaOnoa On Wordpress!!  |  พฤศจิกายน 12, 2011 เวลา 6:22 am

    […] Part I : https://onoaonoa.wordpress.com/2011/10/15/arc-automatic-reference-counting-part-i/ […]

    ตอบกลับ

ใส่ความเห็น

Trackback this post  |  Subscribe to the comments via RSS Feed


del.icio.us For iPhone dev

Post Calendar

ตุลาคม 2011
จ. อ. พ. พฤ. ศ. ส. อา.
 12
3456789
10111213141516
17181920212223
24252627282930
31