Objective-C Programmming :Extending Class

ปัญหาอย่างหนึ่งของการใช้ 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 จะเห็นว่ามันมีประโยชน์มากๆเลยสำหรับการขยายคลาส

Technorati Tags: , ,


Leave a Reply

You must be logged in to post a comment.


5

.

.

1300


.

Total Health Makeover