about bank

วันอังคาร, ธันวาคม 28, 2547

Objective-C and SAX and NSXML and demo

พยายามหา ตัวอย่างการเขียน xml ... หาไม่ได้เลยจริงๆ สุดท้ายต้องงมเอง ได้มาแค่นี้ล่ะ สุดความสามารถ ต้องสร้าง class ขึ้นมาก่อนตัวนึง เพื่อเอาไว้ให้ xml เรียก ไม่รู้ว่า Objective-c มีแบบนี้เป็น pattern หรือเปล่าเพราะใน parser ของ java เราใช้ exception แทน ไม่ได้เป็นแบบนี้

ทดลองใส่ method แค่สามตัวคือ

+ (void)parser:p didStartElement:element
จะถูกเรียกตอนเจอ element เปิด เช่น

+(void)parser:p didEndElement:e namespaceURI:u
จะถูกเรียกตอนเจอ element ปิด เช่น


+(void)parser:p foundCharacters:string {
ถูกเรียกตอนเจอตัวอักษร แม่แต่ช่องว่างก็มาเรียกตัวนี้เหมือนกัน


#import <Foundation/Foundation.h>

@interface HelloWorld:NSObject {

}
@end

@implementation HelloWorld:NSObject

NSString *saxStatus = @"none";
int i=0;

+ (void)parser:p didStartElement:element
namespaceURI:u qualifiedName:q attributes:a {

if ( [element isEqualToString:@"Doc"] ) {
NSLog(@"<Doc>");
saxStatus = @"Doc";
}

if ( [element isEqualToString:@"esearch"] ) {
NSLog(@" <esearch>");
saxStatus = @"esearch";
}

if ( [element isEqualToString:@"tentry"] ) {
NSLog(@" <tentry>");
saxStatus = @"tentry";
}
}

+(void)parser:p didEndElement:e namespaceURI:u
qualifiedName:q {
if ( [e isEqualToString:@"Doc"] ) {
NSLog(@"</Doc>");
//add word to array
i++;
}

if ( [e isEqualToString:@"esearch"] ) {
NSLog(@" </esearch>");
}

if ( [e isEqualToString:@"tentry"] ) {
NSLog(@" </tentry>");
}
}

+(void)parser:p foundCharacters:string {
if([saxStatus isEqualToString:@"esearch"]){
NSLog(@" %@", string);
}

if([saxStatus isEqualToString:@"tentry"]){
NSLog(@" %@", string);
}
saxStatus = @"none";
}

@end

int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Hello, here are world news:\n");

NSString *location;

location = @"file:///Users/bank/programming/etlex_thai_utf8.xml";

NSXMLParser *xml=[[NSXMLParser alloc]
initWithContentsOfURL:
[NSURL URLWithString:location]];

HelloWorld *hwXML = [HelloWorld class];
[xml setDelegate:hwXML];
[xml parse];

[pool release];
return 0;
}


อุตส่าทำตั้งนาน สุดท้ายก็ยังมีปัญหากับภาษาไทยอยู่ดี ต้องแปลงเป็น UTF-8 ก่อน เพราะ nsxml อ่าน TIS-620 ไม่ได้ :( พอแปลงแล้วก็ยังมีปัญหาอยู่ แต่ยังหาสาเหตุไม่ได้ ใตรสนใจเดี๋ยวพรุ่งนี้เอา xml มาลงให้ดู

วันจันทร์, ธันวาคม 27, 2547

วิธีเรียกใช้ Object ให้เข้าทาง Objective-C

ใน mailing list ของ apple นี่ดีจริง วันนี้ก็ได้รับความช่วยเหลืออีกแล้วครับท่าน Andrew ให้คำแนะนำมานิดหน่อย แต่เป็นตัวอย่างที่ช่วยให้คิดอะไรต่อได้มากจริงๆ ครับ

ดู code ตัวเก่าที่เขียนกันวันก่อน


NSAutoreleasePool * pool = [NSAutoreleasePool new];
for (i=0; i<2; i++){
str = [NSString stringWithFormat:@"Double %d",i];

dd3 = [DataDic new];
[dd3 setName:str];

[myArray addObject:dd3];
[dd3 release];
}
[pool release];


จะเห็นว่า str ไม่ได้ถูกชี้ไปที่ NSString ที่ถูก init ก็เลยต้องใช้ AutoreleasePool เข้ามาช่วย จริงๆ ตรงนี้ก็งงๆ นะ เก็บไว้ก่อนละกัน :p

อันนี้ตัวใหม่ที่ดูดีกว่าครับ (ปรับปรุงจากที่ Andrew แนะนำ)


for (i=0; i<2; i++){
str = [[NSString alloc] initWithFormat:@"Double %d",i];

dd3 = [DataDic new];
[dd3 setName:str];

[myArray addObject:dd3];
[dd3 release];
}


ตอนนี้ str ก็ได้ String จริงๆ ไปใช้แล้วครับ :) อีกอย่างหนึ่ง Andrew แนะนำครับ
คือให้เติม method นี้ลงใน DataDic.m เพื่อ optimize code ครับ


- (id)initWithWord:(NSString *)aString {
if (self = [super init]) {
_name = [aString retain];
// this assumes that you have the instance variable '_nord'
// you should also initialise any other instance variables here
}
return self;
}


คิดว่าคงความหมายเดียว constructer หรือแบบเดียวกับ static method ที่เรียก constructor อีกที :p ในภาษา java แต่ใน objective-c ถ้าเราทำแบบนี้ แล้วก็มีดีที่ตัว method จะบอกความเหมายของมันด้วย

ไม่รู้ว่า objective-c จะมี constructer ได้หลายอันหรือเปล่า ไว้ลองวันหลังเนอะ

วันพฤหัสบดี, ธันวาคม 23, 2547

แก้ปัญหา error เกียบกับ memory management

วันนี้คุยกับ xnu พยายามทำให้เกิด bug จาก memory management ก็หาอยู่พักใหญ่เลย จำได้ว่าเคยเจอ error แบบนี้ ก็ได้ความช่วยเหลือจาก xnu ทำให้ได้ bug ตัวนี้มา

อยากให้ลองศึกษาดูครับ คิดว่าเป็นประโยชน์อย่างมาก โดยเฉพาะ กับคนที่เริ่มต้นเขียนโปรแกรมด้วยภาษา Objective-C เพราะจะช่วยให้เราเข้าใจ memory managment กันมากขึ้น

สืบเนื่องจากการ post ครั้งที่แล้วนะ ให้เปลี่ยนส่วนของการใส่ object DataDic ลงใน array ของ main.m


int main (int argc, const char * argv[]) {

NSMutableArray *myArray = [NSMutableArray new];

DataDic *dd3;

int i;

NSAutoreleasePool * pool = [NSAutoreleasePool new];
for (i=0; i<2; i++){
str = [NSString stringWithFormat:@"Double %d",i];
dd3 = [DataDic new];
[dd3 setName:str];
[myArray addObject:dd3];
[dd3 release];
}
[pool release];

DataDic *wd = [myArray objectAtIndex:0];
NSLog(@"wd equal %@", [wd name]);

DataDic *wd2 = [myArray objectAtIndex:1];
NSLog(@"wd2 equal %@", [wd2 name]);

return 0;
}


ตรงนี้จะเกิด error คือค่าใน memory ของเราหายไปครับ เนื่องจากถูก release โดย [pool release] และหลายครั้งที่เราจำเป็นต้องทำ อยางในการอ่าน xml ที่น่าจะ post วันพรุ่งนี้ก็ต้องใช้

วิธีแก้ก็นิดเดียวเอง แค่เปลี่ยน method setName ใน DataDic.m จากแบบนี้


- (void) setName:(NSString *)newName {
_name = newName;
}


ให้เป็นแบบนี้


- (void) setName:(NSString *)newName {
if(_name != newName){
[newName retain];
[_name release];
_name = newName;
}
}


จริงๆ แล้วมันสำคัญอยู่ที่ [newName retain] เพราะเป็นการเพิ่มจำนวนโซ่ (หมายถึงจำนวน pointer ที่ตัวแปลนับอยู่) ให้กับตัวแปลที่ส่งเข้ามา เพื่อให้มันไม่ถูก release เวลาที่ pointer ที่เคยชี้อยู่หายไป

วันอังคาร, ธันวาคม 21, 2547

ทดลองเรียก Object บน Objective-C ครับ

วันนี้ลองทำ Object ที่ง่ายๆ ขึ้นมาเป็นตัวอย่างที่ไม่ค่อยดีเท่าไหร แต่ไว้วันต่อไปค่อยทำตัวอย่างให้ดูละกันว่าแบบนี้มันไม่ดียังไง และในกรณีไหนที่ทำให้ object แบบนี้เกิดความผิดพลาด

เริ่มต้นจากการสร้าง Object ที่จะนำไปใช้ก่อน

// DataDic.h


#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>

@interface DataDic : NSObject {
NSString *_name;
}

- (void) setName:(NSString *)newName;
- (NSString *) name;

@end


เป็น object ง่ายๆ มี name เอาไว้เก็บ String และทำตัวเหมือน private ใน java

// DataDic.m

#import "DataDic.h"

@implementation DataDic

- (void)
setName:(NSString *)newName {
_name = newName;
}

- (NSString *) name {
return _name;
}

@end


ท่อน implement ง่ายกว่า interface :)


#import <Foundation/Foundation.h>
#import <DataDic.h>

int main (int argc, const char * argv[]) {

//work well
NSString *str;

str = @"DoubleA";
DataDic *dd = [DataDic new];
[dd setName:str];

str = @"DoubleB";
DataDic *dd2 = [DataDic new];
[dd2 setName:str];

NSLog(@"dd is %@",[dd name]);
NSLog(@"dd2 is %@",[dd2 name]);

//work with array
NSMutableArray *myArray = [[NSMutableArray alloc] init];

DataDic *dd3;

dd3 = [DataDic new];
[dd3 setName:@"DoubleA"];
[myArray addObject:dd3];

dd3 = [DataDic new];
[dd3 setName:@"DoubleB"];
[myArray addObject:dd3];

DataDic *wd = [myArray objectAtIndex:0];
NSLog(@"wd equal %@", [wd name]);

DataDic *wd2 = [myArray objectAtIndex:1];
NSLog(@"wd2 equal %@", [wd2 name]);

return 0;
}


ตัว main แบ่งออกเป็นสองท่อน ท่อนบน เป็นการนำไปใช้แบบธรรมดา ก็สามารถใช้ได้ไม่มีปัญหา แม้ว่าตัวแปลที่เอามาใส่จะเป็นตัวเดียวกันก็ไม่ทำให้ค่าเปลี่ยนไป

ในท่อนที่สองเราใช้ Array ครับ แล้วก็ใช้ DataDic ตัวเดียวกันในการสร้าง Object ใส่ลงใน Array

พื้นฐาน memory management ใน Objective-c

memory management บน Objective-c ไม่เหมือนกับบน C หรือ C++

Obj-C จะใช้วิธีจำจำนวน pointer ที่ชี้มันไว้ ถ้า pointer เป็น 0 เมื่อไหร ตัว autorelase ก็จะทำการลบมันทั้งครับ สำหรับคำสั่งที่ใช้ในการจัดการ memory ก็มีหลายคำสั่ง เช่น alloc retain release เป็นต้น

เท่าที่คุยกับ rp สรุปได้ว่าว่า

NSString *x = [NSString alloc];
หลักจาก alloc แล้ว ก็เหมือนมีโซ่ผูกคอหมาหนึ่งเส้น

[x retain]
พอสั่ง retain ก็เหมือนมีโซ่อีกเส้นนึงมาผูกคอหมาไว

NSString *y = x;
พอสั่งให้มีตัวแปลเข้ามาชี้ มันแบ่งโซ่ให้กับ y

[y release]
ถ้าสั่ง release ก้เหมือนปลอยโซ่ออกจามือ

[x retain];
[x release];
NSLog(@"dog here %@",x);
ถ้าเรียกมีโซ่อยู๋หลายอัน จะ release ไปสักอันมันก็ยังมีโซ่อยู่ในมือหมาไม่หายไปไหน

จริงๆ มันก็ไม่ได้มีโซ่ หรือแบ่งโซ่อะไรหรอก แค่มันมีตัวเลขเก็บจำนวนโซ่แค่นั้นเอง (ยังเป็นโซ่อยู่ดี) ถ้าไม่เหลือโซ่แล้วตัวแปลของเราก็จะหายไปโดยอัตโนมัติ

* ยังไม่แน่ใจว่าเฉพาะกับ object หรือเปล่า ขอไปลองก่อนนะ
* จะหายไปก็ต้องมีการทำ autorelease ด้วยนะ

convert file type in unix

วันนี้คุยกับ rp แล้วก็ xmu ได้ความรู้ใหม่

คำสั่งสำหรับแปลง file จาก tis-620 ไปเป็น utf-8

iconv -f tis-620 -t utf-8 etlex_thai2.xml >etlex_thai3.xml

แล้วก็ เราสามารถใช้คำสั่ง less เพื่อดูว่า xml นั้น encode ด้วยอะไร

อีกอันก็คือ nsxml ไม่สามารถอ่าน xml ที่ encode ด้วย tis-620