Archive
Objective-C Note ภาคต่อ 3
ใกล้หมดแล้วครับมาต่อกันเลย
ความเข้าใจในการใช้ nil [ Calling methods on Nil]
ใน Objective-C นั้น nil object นั้นมี การทำงานเหมือน NULL pointer ในหลายๆ ภาษาที่แตกต่างไปก็คือเราสามารถ เรียก method ของ nil object โดยไม่ทำให้โปรแกรมล่มหรือทำให้เกิด exception ได้ [” จิงดิ “]
เทคนิคนี้ถูกนำไปใช้ใน Frameworks หลากหลายวิธีการ แต่ความหมายที่ต้องการให้ทราบก็คือในขณะนี้ก็คือเราไม่จำเป็นต้องตรวจสอบ object ก่อนการเรียกใช้ method ว่า object นั้น จะเป็น nil หรือไม่ หากเราเรียก method ของ nil object จะได้ค่า nil เป็นค่า return
เราลองมาดูการปรับปรุง dealloc ให้ดีขึ้นอีกนิส
-(void) dealloc { self.caption = nil; self.photographer = nil; [super dealloc]; }
code ส่วนนี้ทำงานได้เนื่องจากเมื่อเรากำหนดค่า nil ให้ instance variable setter จะทำการ retain ค่า nil (แปลว่าว่างเปล่า)และreleaseค่าเก่าออกด้วยวิธีการนี้จะทำให้ variable หมดโอกาสที่จะชี้สุ่มไป เรื่อยเปื่อย
การที่เราใช้ รูปแบบ self. ก็หมายถึงเรากำลังใช้ setter และให้ memory management ของระบบ จัดการเรื่องการคืน memory ถ้าหากเราใช้แบบกำหนดค่าให้โดยตรง(ตัวอย่าง codeด้านล่าง) จะทำให้เกิด memory leak ได้
// incorrect. Causes a memory leak. // use self.caption to go through setter caption = nil;
Categories
categories เป็น คุณลักษณะที่สำคัญอีกอันหนึ่งของ Objective-C โดยที่ Categories นั้นจะทำให้เราสามารถที่จะเพิ่ม method ให้กับ class ที่มีอยู่โดยที่ไม่ต้องทำ sublassing หรือ รู้รายละเอียดเกี่ยวกับการ implementation ของ class นั้น ๆ เลย
ถือว่ามีประโยชน์มากเนื่องจากเราสามารถที่เพิ่ม method ให้กับ built-in object( object ของ class ใน framework ของ cocoa เอง ) เช่นหากเราต้องการเพิ่ม method ให้กับ instance ของ NSString ใน application ที่เรากำลังทำอยู่ เราแค่เพิ่ม category. เราไม่จำเป็นต้องรู้ทุกอย่างเพื่อทำ subclass ขึ้นมา
ตัวอย่าง ถ้าต้องการเพิ่ม method ให้กับ NSString เพื่อใช้ตรวจสอบว่า string ที่กำหลดให้ขณะนั้นเป็น URL หรือไม่ หน้าตาของมัน จะประมาณนี้ครับ
#import @interface NSString (Utilities) -(BOOL) isURL; @end
จะเห็นว่าหน้าตาเหมือนการประกาศ class จะต้องบอกสักนิสว่า method นี้ใช้แสดงให้เห็นการทำ category เท่านั้นให้ดูเท่านนั้นไม่ใช้ method สำหรับการตรวจสอบ URL ที่ดีเลยไม่ควรเอาไปใช้จิงนะครับ
ครับมาดูว่าเราจะ implement อย่างไร
#import “NSString-Utilities.h” @implementation NSString (Utilitites) -(BOOL) isURL { if([Self hasPrefix:@”http://”]) return YES; else return NO; } @end
ครับตอนนี้เรามาลองดูการใช้งานว่าเป็นอย่างไร
NSString* string1 = @”http://pixar.com/”; NSString* string2 = @”Pixar”; if([string1 isURL]) NSLog(@”string1 is a URL”); if([string2 isURL]) NSLog(@”string2 is a URL”);
ต่างกับ subclass นะครับ category ไม่สามารถ เพิ่ม instance variable ได้ อีกอย่างหนึ่งที่สามารถทำได้คือเราสามารถใช้ category ในการ override method ที่มีอยู่ได้ แต่ต้องทำอย่างระมัดระวังอย่างมากมาย
จะบอกว่าเนื้อหาในเรื่อง Obective-c Mynote จบลงตรงนี่ครับ เรื่องที่กล่าวมาทั้งหมดนั้นอ้างอิง หรือ แปลจาก http://www.cocoadevcentral.com เพื่อน ๆ สามารถหาอ่านเพิ่มเติมได้ที่นี่และ ค้นหาได้ใน internet
ในเรื่องของการเขียนโปรแกรมกับ Objective-c นั้นส่วนต้วผมเป็นเรื่อสนุกและท้าทายนะครัย ที่กล่าวมาทั้งหมดนั้นเป็นพื้นฐานของการเขียนObjective-c เรายังต้องเรียนรู้เพิ่มอีกในเรื่องของ cocoa (เขาออกเสียงว่า โกโก้ หรือปล่าวไม่รู้นะ) และ cocoa graphic
Cocoa นั้นเป็นกลุ่มของ Framework ซึ่งประกอบด้วย Foundation, AppKit และ CoreData เป็นต้น จะช่วยให้เราพัฒนา application ให้กับ MAC OS X ซึ่งเป็นที่ทราบกันว่าเทคโนโลยีบางส่วน นั้นสืบทอดมากจาก NeXTSTEP operating system ครับค่อยพูดกันในรายละเอียดใน บทความ ต่อ ๆอีกก็แล้วกันนะครับ
ธีระพงษ์ สนธยามาลย์
s.teerapong@gmail.com
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