ARC (Automatic Reference Counting) Part II

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

เอาละครับ ในเรื่องของ 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 ครับ ;)

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

Movie : Top Secret วัยรุ่นพันล้าน [Diary] Treasure from flood.

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

  • 1. ARC (Automatic Reference Counting) Part I « OnoaOnoa On Wordpress!!  |  พฤศจิกายน 12, 2011 ที่ 6:25 am

    […] ARC (Automatic Reference Counting) Part II […]

    ตอบกลับ
  • 2. cpreKMUTNB  |  เมษายน 25, 2012 ที่ 9:13 am

    ผมก็ยังเป็นคนนึงที่ยังไม่เชื่อใจ ARC ผมเลยยังใช้ dealloc method และ release เองอยู่
    ประเด็นก็คือว่า การที่เรา Create Project แล้วใช้ ARC จากนั้นถ้าเกิดลอง Create NewFile ที่เป็น UIViewController ปัญหาคือ มันไม่มี dealloc method
    ถ้าจะสร้างเองก็ได้แหละครับแต่คงต้องเอา [super dealloc] ออกไป
    แต่เรื่องหลักๆแล้วที่อยากจะถามมีดังนี้ครับ
    1) ถ้าเกิดผมไม่ใช้ dealloc method มันจะ release ให้ผมมั้ยครับถ้าเกิด ผม สั่ง release ViewController นั้น [self release] แบบนี้อ่ะครับ ตามแนวคิดของ ARC ที่คุณบอกว่ามันจัดการให้
    2) หลักการ release ของ ARC มันจะ release เฉพาะตัวแปรที่ผมประกาศเป็น property หรือ global รึป่าว
    3) ถ้าเกิดว่าผมประกาศเป็น local variable แต่ผมอาจจะ ใส่เป็น __strong หรือ __weak มันจะ release ตัวแปร พวก local ให้มั้ยครับ ตาม หลัก ของ ARC
    ขอบคุณล่วงหน้านะครับ เพราะผมสงสัยเรื่องนี้มากเลย เพราะ โปรแกรมผม มัน switch view ไปหลายๆหน้า ดังนั้นก่อน switch มันจะ release ตัวเองก่อน จาก [self release] อ่ะครับ ถ้าเกิด ARC มันจัดการตัวแปร ที่ผมประกาศไว้ให้ด้วยก็คงจะวิเศษเลยหละครับ ขอบคุณมากนะครับ

    ตอบกลับ
    • 3. Jerapong Nampetch  |  เมษายน 26, 2012 ที่ 11:39 pm

      1) ถ้าคุณเซตโปรเจคคุณให้ใช้ ARC จัดการ memory management คุณก็ใช้คำสั่ง -release กับ ViewController นั้นเองไม่ได้อยู่แล้วนิครับ เพราะมันจะจัดการให้อัตโนมัต
      2) ทั้งหมด ทั้ง class variable และ local variable ครับ
      3) มันจะ release ให้ครับ ถ้าไม่ใส่อะไร มันก็จะถือว่าเป็น __strong ครับ

      ส่วนเรื่อง app ของคุณที่สลับ View ไปหลายๆหน้า อันนี้ต้องระวังนิดนึงครับ ปัญหาที่ผมเคยเจอคือด้วยความที่มันจัดการอัตโนมัติ บางครั้งการทำ Lazy load ก็มีปัญหาอย่างไม่เคยเป็น (dangling pointer) อย่างเคส View นี่ก็เหมือนกัน ตอนเข้าใช้ได้แต่ตอน back ดันโดน release ไปแล้วต้องจัดการดีๆหน่อยครับ

      ตอบกลับ
  • 4. win  |  มิถุนายน 16, 2012 ที่ 12:46 pm

    รบกวนถามหน่อยครับ ถ้าสมมุติ ประกาศใช้ strong
    แบบนี้ @property (strong, nonatomic) ViewController *viewController;
    เข้าใจว่าเราไม่ต้อง release เอง

    แล้วใน method dealloc ยังต้อง release ไหมครับ
    – (void)dealloc
    {
    [_viewController release];
    [super dealloc];
    }
    หรือไม่ต้องแล้วครับ

    ตอบกลับ

ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  เปลี่ยนแปลง )

Google photo

You are commenting using your Google account. Log Out /  เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out /  เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out /  เปลี่ยนแปลง )

Connecting to %s

Trackback this post  |  Subscribe to the comments via RSS Feed


del.icio.us For iPhone dev

Post Calendar

พฤศจิกายน 2011
พฤ อา
« ต.ค.   ธ.ค. »
 123456
78910111213
14151617181920
21222324252627
282930  

%d bloggers like this: