ปัญหาอย่างหนึ่งของการใช้ Framework หรือ Library ต่างๆก็คือ เราไม่อาจจะไปแก้ไขหรือเพ่ิมเติม method ต่างๆของ class ได้ เพราะว่าบางครั้ง Lib ที่ได้มานั้นก็มีแต่ lib ที่ผ่านการ compile เป็น binary files และมีแค่ header มาเท่านั้น วิธีการที่่เราจะเพิ่มเติมเข้าไปได้ก็คือ ต้องเขียน subclass ของ class นั้นๆ แต่ในภาษา Objective-C นั้นมีอีกวิธีหนึ่งที่เราสามารถเขียน method เพิ่มเติมเข้าไปยัง class เดิมได้ นั่นก็คือ category
สมมติว่าเราต้องการเขียน โปรแกรมที่ต้องการ reverse string บ่อยๆ เราอาจจะเขียน class ขึ้นมาใหม่และเขียน method ที่ชื่อว่า getReverse ขึ้นมา อาจจะเขียนได้ประมาณนี้ ได้ว่า
@interface ReverseString:NSObject { NSString* m_text; } -(void) setString:(NSString*) text; -(NSMutableString*) getReverse; @end
แล้วก็เขียน code ในส่วนของ getReverse ได้ว่า
@implementation ReverseString -(NSMutableString*) getReverse { NSMutableString *temp = [[[NSMutableString alloc] init] autorelease] ; unichar c; for(int i = [m_text length]-1 ; i >= 0 ; i-- ) { c = [m_text characterAtIndex:i]; [temp appendString:[NSMutableString stringWithCharacters:&c length:1]]; } return temp; } @end
เขียนแบบนี้ก็พอได้ แต่ว่ามันก็มีข้อเสียคือ เมื่อเราต้องการจะ reverse string เราต้องให้ตัวแปร ของเราเป็น ReverseString
ReverseString *hello = [[ReverseString alloc] init]; [hello setString:@Hello]; NSMutableString *revHello = [hello getReverse];
ซึ่งมันไม่สะดวก วิธีที่ดีกว่านั้นก็อาจจะเขียนเป็น function ขึ้นมาเป็น global ก็พอได้
แต่ถ้าหากเราอยากจะทำให้ NSMutableString มี method ที่ชื่อว่า getReverse เลยจะทำได้ไม๊ ?
คำตอบก็คือ ทำได้
Category นั้นทำให้เราสามารถที่จะเพิ่ม method ต่างๆเข้าไปยัง class ที่มีอยู่เดิมที่เราไม่สามารถจะไปแก้ไขในส่วนของ source ได้ แต่ Category ก็ไม่ได้สิทธิมากขนาดที่จะไปเพิ่ม member ใน Class ได้ เรามาลองดูการใช้ Category เลยอาจจะเข้าใจง่ายกว่า
จากตัวอย่างข้างบนนั้นถ้าหากเราต้องการจะเขียนให้ NSMutableString มี method นั้นเราก็ต้องเขียน category ขึ้นมาวิธีการ ก็สุดแสนจะง่ายดายเพียงแค่ โดยมีรูปแบบดังนี้
@interface ClassName ( CategoryName )
เอาละมาดูของจริงกันเลยดีกว่า ก่อนอื่นเราก็ประกาศ Category ที่ชื่อว่า MyExtend โดยเราจะเพิ่มเติมขยายในส่วนของ NSMutableString และเราก็เขียน method ใหม่ที่ชื่อว่า getReverse
// MyString.h @interface NSMutableString (MyExtend) -(NSMutableString*) getReverse; @end
หลังจากนั้นก็เขียน ในส่วนของ source ได้แบบนี้
// MyString.m @implementation NSMutableString (MyExtend) -(NSMutableString*) getReverse { NSMutableString *temp = [[[NSMutableString alloc] init] autorelease] ; unichar c; for(int i = [self length]-1 ; i >= 0 ; i-- ) { c = [self characterAtIndex:i]; [temp appendString:[NSMutableString stringWithCharacters:&c length:1]]; } return temp; } @end
เพียงแค่เท่านี้ก็เสร็จเรียบร้อย หลังจากนั้นแล้ว NSMutableString ของเราก็จะมี method ใหม่ที่ชื่อว่า getReverse เรียบร้อยแล้ว
การเรียกใช้ก็ไม่ได้ยาก ดังตัวอย่าง
#import "MyString.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSMutableString *text = @"Hello"; NSLog(@"%@",[text getReverse]); [pool drain]; return 0; }
และนอกจากนี้เรายังสามารถใช้ category เพื่อทำเป็น private method ได้ด้วย สมมติว่าเรามี Class ง่ายๆแบบนี้
//AA.h @interface AA : NSObject { } -(int) getSomeInt; @end
และเขียน implement ง่ายๆแบบนี้
//AA.m @implementation AA -(int) getSomeInt { return 10; } @end
จะเห็นว่า AA นั้นมี getSomeInt ซึ่งเป็น public method และในกรณีที่เราอยากให้มันเป็น private เราอาจจะดัดแปลงได้โดยการใช้ category ได้แบบนี้
//AA.m @interface AA(hidden) -(void) getHiddenInt; @end @implementation(hidden) -(void) getHiddenInt { return 20; } @end @implementation AA -(int) getSomeInt { return 10; } @end
เป็นไงบ้างครับสำหรับการใช้ category จะเห็นว่ามันมีประโยชน์มากๆเลยสำหรับการขยายคลาส


