Posts tagged ‘ARC’

ARC (Automatic Reference Counting) Part II

เอาละครับ ในเรื่องของ ARC ตอนที่ 1 ผมอธิบายคร่าวๆไปแล้วว่ามันคืออะไร มีดียังไง ใน Entry นี้ ผมจะลงลึกรายละเอียดของ ARC มากขึ้น เพื่อรีดเค้นประสิทธิภาพของ ARC ให้มันดียิ่งขึ้นไปอีก ใครอยากอ่านตอนเก่าอยู่ ดูที่นี่ได้เลยครับ

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

เอาละครับ เริ่มกันเลย

ก่อนหน้านี้ ผมเคยเปรียบเทียบการใช้ ARC กับการลดหุ่น ซึ่งใช้การควบคุมอาหารเป็นหลัก ถ้าเรากินอาหารแต่พออิ่มไม่กินมากเกินไป ไม่กินเป็นบุฟเฟต์ เราก็ควรจะมีหุ่นสมส่วนไม่อ้วนไม่ผอม ซึ่งก็เหมือนกับการใช้ ARC แบบ default คือระบุเป็น strong type ทั้งหมด แน่นอนว่าโปรแกรมเราทำงานปกติ และโอกาสเกิด memory leak ก็ไม่น่าจะมี เพราะ ARC จะจัดการให้เราตามหลัก ถูกมั้ยครับ?

งั้น ลองคิดดูว่า เรากินแต่พออิ่มเหมือนเดิม ข้าวจานเดียว น้ำแก้วเดียว ผลไม้อีกจานนึงต่อมื้อ แต่เรากิน ข้าวขาหมู+เป๊ปซี่+ทุเรียน คุณยังคิดว่าเราจะผอมอยู่มั้ย? ไม่แน่นอน อาหารแคลลอรี่สูงเหล่านี้ไม่ช่วยให้คุณผอมได้แม้จะกินแค่พออิ่ม …ARC ก็เช่นกันครับ การที่เราจัดการตัวแปรแบบ strong ทั้งหมด  นั่นก็ทำให้ใน App เราใช้ memory เยอะในช่วงเวลา runtime เพราะค่าทุกค่าถูกเก็บไว้ตลอดและจะถูกปล่อยคืนเมื่อ App ปิดตัวลง นี่เป็นสาเหตุที่เราต้องจัดการ ARC แม้ว่ามันจะบอกว่าเป็น Automatic อยู่ก็ตาม

type ของ ARC หลักๆ คือ strong กับ weak ถ้าเรากำหนด type strong ให้กับตัวแปร สบายใจได้ว่า value ของตัวแปรนี้ จะไม่หายไปหรือเปลี่ยนไปเป็นอย่างอื่นแน่นอน ตราบที่ไม่เราไม่เป็นคนไปเปลี่ยนเอง แต่ข้อเสียก็คือ เปลือง memory เพราะจำค่านั้นๆตลอดเวลาที่แอพทำงาน และยิ่งกว่านั้นคือ “ทำให้เกิด memory leak ได้ด้วย”

…เป็นไปได้อย่างไร? แต่เป็นไปได้ครับ เช่นในกรณีที่มีการ reference หากับแบบ parent กับ child อย่าง delegate หรือ datasource ใน UITableView เป็นต้น ลองดูเคสนี้ครับ สมมุติว่า myTableView ระบุให้ ARC จัดการ “delegate, datasource แบบ strong ทั้งหมด” ลองนับดูนะครับว่า Object “MyArcLeak” ที่เราสร้างขึ้น จะมี retain count เท่าไหร่เมื่อโค้ดผ่าน -viewDidLoad ไป โดยเริ่มต้นจาก 1 จากการ allocate object


@implementation MyArcLeak
- (void)viewDidLoad {
[super viewDidLoad];
self.myTableView.delegate = self;     // retain count + อีก 1
self.myTableView.datasource = self;   // retain count + อีก 1
}

จะเห็นว่า object ที่เราสร้างขึ้นมี retain count กลายเป็น 3!! เมื่อ arc release object ที่เราสร้างขึ้น มันก็ลบ retain count ออกไป 1 เท่านั้น เห็นมั้ยครับว่าแม้จะใช้ ARC ก็ยัง Memory leak ได้อยู่ นี่เป็นเหตุผลที่เราต้องรู้จักการใช้ ARC ทั้ง strong และ weak

strong อธิบายไปแล้ว แล้ว weak เป็นอย่างไร? ผมบอกไปแล้วว่า weak type เป็น type ที่ค่าจะถูกเปลี่ยนเป็น nil ได้ตลอดเวลา ซึ่งตลอดเวลาที่ว่าคือ เมื่อ value ที่ weak variable ชี้ไปหาถูกเปลี่ยนไปเมื่อไหร่ weak variable จะถูกเปลี่ยนเป็น nil ทันที ลองดูโค้ดตามนี้ครับ


NSString *a = @"strong";
__strong NSString *b = a;
a = @"A is Strong";

ผลที่ได้คือ a => A is Strong และ b => strong

แต่ถ้า b เป็น weak type ผลที่ได้จะต่างออกไปดังนี้


NSString *a = @"strong";
__weak NSString *b = a;
a = @"A is still Strong";

ผลที่ได้จะเป็น a => A is still Strong และ b => nil

นี่แหละครับ ความต่างของ strong และ weak และจะต้องใช้แบบไหนยังไง สรุปแบบสั้นๆง่ายๆครับ

  1. ถ้าเป็นพวกที่เมื่อก่อน property assign เมื่อไหร่ ก็ใช้ __weak ครับ เช่น delegate, datasource
  2. ถ้าเป็นตัวแปรที่ reference จาก xib หรืออะไรก็ตามที่เป็น IBOutlet ให้ตั้งเป็น weak เสมอ เพราะ Object ถูก retain ด้วย IB อยู่แล้ว

หลักๆสองข้อเท่านี้แหละครับ หลักของการใช้ weak แบบทั่วไป แต่คราวนี้ยังมีิอีกอย่างที่ยังคงต้องพูดถึง ปัญหาอีกอย่างนึงที่ยังคงอยู่คือเรื่อง iOS4 กับ ARC ครับ

จริงอยู่ว่า ARC support iOS ตั้งแต่เวอร์ชั่น 4 ขึ้นไป เท่าที่ apple support iOS version จนถึงปัจจุบันนี้ แต่ข่าวร้ายคือ iOS4 ไม่ support ARC type แบบ weak ครับ วิธีการแก้ไขคือ เราต้องใช้ ARC type แบบ __unsafe_unretain แทน เท่านี้แหละครับใช้ได้แล้ว ดูเหมือนไม่มีปัญหา แต่จริงๆก็มีครับ unsafe_unretain ต่างกับ weak แค่ตรงที่ เวลาที่ value ต้นทางเปลี่ยน มันไม่เป็น nil ให้เหมือน weak ครับ

เพราะเหตุนี้เองมันถึงได้ unsafe ที่ว่าไม่ปลอดภัย เพราะการที่ pointer ชี้ไปตำแหน่งที่ไม่ถูกต้องตามค่าที่คาดการณ์ไว้นั้น อาจจะทำให้เกิดบั๊กที่เรียกว่า Dangling pointer และทำให้ application crash ตามมาใน worst case การแก้ไขคือเราก็ต้องตรวจสอบให้ดีๆ อาจใช้ tool ใน instrument หรือเปิด feature zombie เพื่อหาข้อผิดพลาดได้ครับ

เอาละครับ สำหรับเรื่อง ARC ตอนที่ 2 ผมก็ได้อธิบายเกี่ยวกับรายละเอียดของการใช้ ARC ทั้ง 3 type ที่จำเป็นและอาจจะได้เจอบ่อยๆ ได้แก่ strong, weak และ unsafe_unretain ซึ่งต้องเจอแน่ๆ 80% ในการพัฒนา iOS application ณ เวลานี้

จริงๆแล้ว ยังมีรายละเอียดอีกเกี่ยวกับ ARC เรื่อง เช่น bridge, การใช้ arc กับ block variable แต่ขอเก็บไว้ Entry หน้าแล้วกันครับ กลัวว่าจะหนักเกินไป หวังว่าจะสนุกกับการสร้างหุ่นสวยๆให้กับแอพของคุณด้วย ARC นะครับ …Happy  Coding ครับ ;)

พฤศจิกายน 12, 2011 at 6:22 am 4 ของความคิดเห็น


del.icio.us For iPhone dev

Post Calendar

สิงหาคม 2019
พฤ อา
« ธ.ค.    
 1234
567891011
12131415161718
19202122232425
262728293031