[Objective-C myNote] ภาคต่อ 1
หายไปนานแสนนานไม่ได้เข้ามา update เลย นานที่ว่าหน่วยไม่ใช่เป็นเดือนนะครับ หน่วยเป็นปี ฮะ ฮะ สำหรับ Note ที่ทิ้งค้างไว้ ก็จะมาต่อกันให้จบในคราวนี้แหละครับ สำหรับคราวที่แล้วนั้นมาจบตรงที่ การออกแบบ class interface – Designing a Class interface
เริ่มที่ หัวข้อนี้ใหม่เลย ครับ
การออกแบบ class interface – Designing a Class interface
การสร้าง class มี 2 ส่วนคือ
- Class interface เก็บไว้ใน ClassName.h
- Define instance variable and public methods
- Implementation เก็บไว้ใน ClassName.m
- Actual code
- Private method ซึ่ง ใช้ภายใน
ตัวอย่าง class ชื่อ photo
#import <Cocoa/Cocoa.h> @interface Photo : NSObject { NSString* caption; NSString* photographer; } @end
– ใช้ #import directive เพื่อบอก compiler ว่าจะเรียกใช้ library อะไร
– @interface บอกว่าเป็นการ ประกาศ class ชื่อ photo colon บอกว่า photo มี superclass เป็นอะไร
– ใน curly bracket ประกาศ variable 2 ตัว ชื่อ caption, photographer ซึ่งเป็น NSString
– จบด้วย @end
ลองมาเพิ่ม getter ให้กับ instance variable กันครับ
#import <Cocoa/Cocoa.h> @interface Photo : NSObject { NSString* caption; NSString* photographer; } caption; photographer; @end;
จำได้ไหม ครับว่าโดยการปฏิบัติทั่วไปแล้ว method ของ Objective-C นั้นจะไม่ใส่ส่วนนำ หรือ prefix “get” single dash “-” นำหน้าชื่อของ method นั้นหมายถึง ชื่อนั้นเป็น instance method ส่วนเครื่องหมาย “+” หรือ plus นำหน้่า method ก็หมยถึง ชื่อนั้นเป็น class method
lass method หมายถึง class ที่สามารถถูกเรียกใช้ได้ในขณะที่ไม่ได้เป็น object หรือ class method ก็คือ static method
สมมุติ เรามี class ชื่อว่า MathFunc ดังนี้
@interface MathFunc : Nsobject { } +(int) square:(int)num; @end @implementation MathFunc +(int) square: (int)num { return num*num; } @end
ดังนั้นการเรียกใช้จะเป็นดังตัวอย่างครับ โดยที่เราไม่ต้องมีการ instantiate ให้เป็น object เราก็สามารถเรียกใช้ฟังก์ชันได้ ( นี่เป็นการแสดงความหมายและการใช้งาน class method )
value = [[square alloc] num:5] ;
โดย default แล้ว compiler จะกำหนดชนิดของค่าที่ส่งกลับหรือค่าที่ return ของ method ใน Objective-C ให้เป็น ชนิด id จาก code ข้างบนการประกาศ method แบบนั้นในทางเทคนิคแล้วถูกต้องไม่ผิดอะไรแต่มันดูไม่ค่อยปกติ เราควรจะกำหนดชนิดของค่า return ให้เจาะจงไปเลยว่าเป็นชนิดใดดังนี้
#import @interface Photo : NSObject{ NSString* caption; NSString* photographer; } -(NSString*) caption; -(NSString*) photographer; @end;
ลองมาเพิ่ม getter ให้กับ instance variable กันครับ
#import @interface Photo : NSObject{ NSString * caption; NSString * photographer; } -(NSString*) caption; -(NSString*) photographer; -(void) setCaption: (NSString*)input; -(void) setPhotographer:(NSString*)input; @end
setter ไม่มีการ return ค่า เราจึงกำหนดด้วย void เหมือนภาษา C
การ Implement class (Class implementation)
มาทำการ Implementation โดยเริ่มที่ getter กันครับ
#import “Photo.h” @implementation Photo -(NSString*) caption{ return caption; } -(NSString*) photographer{ return photographer; } @end
ในส่วนของการ implementation นั้น กำหนดด้วย @implementation ตามด้วยชื่อ class ลงท้ายด้วย @end ลักษณะการเขียนเหมือนกับ interface method ที่ต้องการ implement ทั้งหมดจะต้องอยู่ระหว่าง 2 statement นี้นะครับ ส่วนของ getter นั้น ก็จะค่อนข้างคุ้น และง่ายต่อการเขียน
ต่อไปดูที่ setter ซึ่งเป็นส่วนที่จะต้องอธิบายเพิ่มเติมจาก code ที่แสดงให้ดู ดังนี้
-(void) setCaption: (NSString*)input { [ccaption autorelease]; caption = [input retain]; } -(void) setPhotographer:(NSString*) input { [photographer autorelease]; photographer = [input retain]; }
setter แต่ละตัวจะเห็นว่าต้องเกี่ยวข้องกับตัวแปร สองตัว ตัวแรกคือ ตัวที่อ้างอิงไปที่ ตัวแปรของ object เอง เช่น caption ส่วนตัวแปรที่ สองเป็น input ใน environment ที่เป็น garbage collected เราสามารถกำหนดค่าใหม่ได้โดยตรง เช่น
-(void) setCaption:(NSString*) input{ caption = input; }
แต่ถ้่หากเราไม่สามารถใช้ garbage collection ได้เราต้องทำการ release ค่าเก่า แล้วกำหนดค่าใหม่ให้ด้วย เครื่องหมาย autorelease และ retain ตามตัวอย่างครับ
การ ปล่อย หรือ free ข้อมูลการอ้างอิง (reference) ไปยัง object นั้นมี 2 วิธีคือ release และ autorelease
สำหรับ release นั้นจะทำการกำจัด reference ทันที ส่วน autorelease นั้นจะทำการกำจัดหลังจาก ระยะเวลาหนึ่ง และจะต้องหลังจากที่ function นั้นจบลงแล้วด้วย นอกจากจะมีการเปลี่ยนแปลงเพิ่มเติม
** autorelease method ใช้กับ setter ดูจะปลอดภัยกว่าเพราะว่าตัวแปรสำหรับค่าเก่าและค่าใหม่นั้นสามารถชี้ไปยัง object เดียวกันได้ หรือ ที่ตำแหน่งเดียวกันเราไม่จำเป็นต้องทำการ release object ที่เราต้องการ retain ค่า ทันทีทันใดก็ได้
ครับดูจะสบสน ในตอนนี้ แต่หลังจากผ่านไปสักระยะหนึ่งก็จะพอเข้าใจขึ้นนะครับ เราไม่จำเป็นต้องเข้าใจทุกสิ่งอย่างทั้งหมดในตอนนี้
Init
เราสามารถ ใช้ Init method สำหรับการกำหนดค่า เริ่มต้นให้กับตัวแปร instance ได้
-(id) init { if( self = [super init]) { [self setCaption:@”Default caption”]; [self setPhotographer:@”Default Photographer”]; } return self; }
code ค่อนข้างจะอธิบายการทำงานได้ดีอยู่แล้ว ยกเว้นในส่วนของ if( self=[super init]) ซึ่งมีลักษณะการใช้เหมือนการ assign ค่า [super init] ให้กับ self ในความรู้สึกมันแปลก ๆ
อธิบายได้ว่า เป็นการร้องขอให้ superclass ทำการ initialization ตัวเอง ส่วน if statement นั้นจะตรวจสอบว่าการ initialization นั้นสำเร็จหรือไม่ก่อนการ กำหนดค่าให้กับ self
Dealloc
Dealloc method นี้จะถูกเรียกเมื่อ object กำลังถูก remove จาก memory ซึ่งเป็นการดีที่จะทำการปล่อย reference ต่าง ๆ ที่อ้าอิงอยู่ออกไปด้วย
-(void) dealloc { ; [photographer release]; [super dealloc]; }
สองบรรทัดแรกนั้นเป็นการปล่อยหน่วยความจำในส่วนของ instance variable เราไม่ใช้การ autorelease ใช้ release จะเร็วกว่า
บบรทัดสุดท้ายนั้นสำคัญมาก เราจะต้องทำการ ร้องขอไปยัง superclass ให้ทำการปล่อยหน่วยความจำในส่วนของตัวเองด้วย หากเราไม่ทำขั้นตอนนี้ object จะไม่ถูกกำจัด ทำให้เกิด memory leak.
Dealloc method นั้นจะไม่ถูกเรียกให้ทำงานหาก garbage collection ทำงาน เราจะทำ finalizeแทน ครับในส่วนของการจัดการ memory นั้นจะขอเพิ่มเติมในรายละเอียดภายหลัง
การบริหารจัดการกับ memory เบื้องต้น [ Basic Memory Management ]
ถ้าหากเรากำลังพัฒนา application บน MAC OS X เราสามารถที่จะเลือกให้ garbage collection ทำงานได้ หมายความว่า จะทำให้เราไม่ต้องมาคำนึงถึงเรื่องการจัดการ memory จนกว่าเราจะเข้าสู่การเขียนแบบที่ซับซ้อนขึ้น เรามาเรียนรู้กันสักนิดหนึ่งนะครับ
ตั้งแต่นี้ไป สำคัญนะครับ
หากเราสร้าง object แบบใช้ alloc เราต้องทำการ release object นั้นหลังจากที่ใช้งานเสร็จแล้ว และสิ่งที่สำคัณอีกอย่างหนึ่งก็คือจะต้องไม่ ไป release object ที่ ถูกกำหนดเป็น autorelease object เพราะว่าจะทำให้ application นั้นล่มเอาง่าย ๆ
// string1 will be release automatically NSString * string1 = [NSString string]; // must release this when done NSString * string2 = [[NSString alloc] init]; [string2 release]
สำหรับ tutorial นี้ให้จำไว้ว่า object แบบ autorelease นั้นจะถูกกำจัดเมื่อจบ funciton นั้น
มีหลายสิ่งที่เราต้องเรียนรู้เกี่ยวกับการจัดการ memory ซึ่ง ความเข้าใจจะมากขึ้นเมื่อเราได้เรียนรู้หรือเข้าใจ concept เพิ่มเติมจากนี้
จบลงตรงนี้ก่อนนะครับ ค่อยต่อกันตอนต่อไปนะครับ
s_teerapong2000@yahoo.com