Objective-C Note ภาคต่อ 2
ยังไม่หมดนะครับเรายังมีหัวข้อที่หน้าสนใจและควรรู้เป็นพื้นฐานต่ออีก สำหรับผู้ที่สนใจใฝ่เรียนรู้หรือต้องการนำไปใช้จริงจังกับการพัฒนางาน โปรแกรมใช้บน MAC OS หรือ IOS ก็ตามนะครับ แล้วแต่ความสะดวก
การจัดการ Memory Management เพิ่มเติมจากเดิม
การจัดการ memory ของ Objective-C เรียกว่า reference counting สิ่งที่เราต้องทำก็คือติดตาม reference ของเรา และในระหว่าง runtime จะต้องมีการทำ free memory
พูดให้ง่ายก็คือ เราทำการจอง (alloc) memory ให้ object และเก็บค่าไว้ระหว่างใช้งาน (retain) แล้วทำการ คืนกลับ (release) หลังจากเลิกใช้แล้ว ให้ทำทุกการทำ alloc และ retain
หมายความว่า หาก เราทำการ alloc ครั้งหนึ่ง retain ครั้งหนึ่ง เราจะต้องทำการ release ถึง 2 ครั้งตามภาพ
ภาพจาก http://www.cocoadevcentral.com/
ที่กล่าวมาเป็นทฤษฎีของ reference counting ในทางปฏิบัติ เรามีเหตุผลในการสร้าง object อยู่ 2 เหตุผลก็คือ
1. เพื่อใช้งานเป็น instance variable
2. ใช้งานภายใน function หรือภายใน method ของ object
โดยมากแล้ว setter ของ instance variable ควรจะทำแค่การ กำจัดค่าเก่า แบบ autorelease และ retain ค่าใหม่ เพื่อความมั่นใจเราควรที่จะทำการ release มันใน dealloc อีกที ด้วย
งานที่ต้องทำจริง ๆ คือการจัดการกับ local references ใน method หรือ function และก็มีกฏเพียงข้อเดียวเท่านั้นก็คือ ถ้าหหากเราสร้าง object ด้วย alloc หรือ copy ให้ทำ release หรือ autorelease ที่ท้าย function แต่ถ้าหากเราสรา้ง object ด้วยวิธีอื่น ๆ ที่ไม่ได้พูดถึง ไม่ต้องทำอะไร
ตัวอย่างนี้ สำหรับกรณีในข้อ 1 (instance variable )
-(void) setTotalAmount:(NSNumber *)input { [totalAmount autorelease]; totalAmount = [input retain]; } -(void) dealloc { [totalAmount release]; [super dealloc]; }
จะเห็นว่าเรามี totalAmount เป็น instance variable และมีการ กำหนดค่าด้วยการ retain เราทำการ release มันอีกครั้ง ใน dealloc ถึงแม้เราจะกำหนด autorelease ให้มันก็ตาม
ตัวอย่างต่อไปก็คือกรณีถัดมาในข้อ 2 การจัดการกับ local reference สิ่งเดียวที่เราต้องทำก็คือ release object ที่ถูกสร้างด้วย alloc
NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75]; NSNumber*value2 = [NSNumber numberWithFloat:14.78]; // only release value1 , not value2
และตัวอย่างนี้ แสดงให้เห็นการใช้ local reference กำหนดค่าให้กับ instance variable ของ object
NSNumber* value1 = [[NSNumber alloc] initWithFloat:875]; [self setTotal:value1]; NSNumber*value2 =[NSNumber numberWithFloat:14.78]; [self setTotal:value2]; [value1 release];
สังเกตุวิธีการใช้กฏ สำหรับการ จัดการกับ local reference นั้นเหมือนกัน ไม่ต้องใส่ใจว่าเราใช้มันกำหนดค่าให้กับ instance variable หรือไม่ และเราก็ไม่ต้องสนใจว่า setter นั้นมีหน้าตาเป็นอย่างไร
ถ้าเราเข้าใจจุดนี้เราก็จะเข้าใจ 90% ของสิ่งที่ควรรู้ เกี่ยวกับการบริหารจัดการ memory ใน Objective-C จบปะ
Properties
อย่างที่เราได้ทำการ เขียน accessor method ให้กับ caption และ author ก่อนหน้านั้น เราอาจจะสังเกตุได้ว่า code นั้นค่อนข้างตรงไปตรงมาน่าจะสามารถทำให้เป็นรูปแบบที่ generalized ได้
Properties คือคุณลักษณะที่มีอยู่ใน objective-C ที่จะทำให้เราสามารถสร้าง accessor ได้อัติโนมัติ และนอกจากนี้ยังมีประโยชน์ข้างเคียงอืนๆอีก เรารองมาแปลง Photo class ให้ใช้ properties กันดู
ก่อนหน้ามีหน้าตาแบบนี้
#import @interface Photo : NSObject { NSString* caption; NSString* photographer; } -(NSString*) caption; -(NSString*) photographer; -(void) setCaption:(NSString*) input; -(void) setPhotographer:(NSString*)input; @end
ซึ่งเมื่อแปลงแล้วจะได้หน้าตาแบบนี้
#import @interface Photo : NSObject { NSString* caption; NSString* photographer; } @property (retain) NSString* caption; @property (retain) NSString* photographer;
@property คือ directive สำหรับการประกาศ property
“retain” ในเครื่องหมายวงเล็บเป็นการกำหนดว่า setter ต้องเก็บค่า input ไว้ และส่วนที่เหลือของบรรทัดนั้นเป็นการกำหนด ชนิด (type) และ ชื่อของ property;
ต่อไป ลองมาดูว่าหากใช้ @property จะต้องimplement class อย่าไร
#import “Photo.h” @implementation Photo @syncthesize caption; @syncthesize phtographer; -(void) dealloc { ; [photographer release]; [super dealloc]; } @end
@synthesize directive จะทำหน้าที่ในการ สร้าง setter และ getter ให้อัตโนมัติ ดังนั้นสิ่งที่เราต้องทำให้ class นี้แค่การ implement dealloc method
สิ่งที่ควรทราบก็คือ accessor จะถูกสร้างขึ้นในกรณีที่มันไม่มีเท่านั้นเราสามารถที่จะ กำหนด @synthesize ให้กับ propertiy ไว้พร้อมกับการ implement setter และ getter ของเราเองได้ ถ้าเราต้องการ หน้าที่ของ compiler คือการเติม ในส่วนที่เราขาดไป ครับ (เป็นทั้งข้อดี และ ข้อเสียนะเนี่ยย)
อย่างไรก็ตาม เรื่องของ property นี้มีรายละเอียดเพิ่มเติมอีกมากครับ ควรจะต้องศษกาาเพิ่มเติมเพื่อการใช้งานที่ดีนะครับ
ถ้าจะให้ดีก็ ว่ากันต่อไปใน คราวหน้านะครับ
ธีระพงษ์ สนธยามาลย์
s.teerapong@gmail.com