Mac Cafe’


Question To me
June 25, 2008, 2:38 am
Filed under: Talk

หลังจากเขียนไปได้สักพักใหญ่ๆ ก็มีคนเข้ามาอ่านเยอะ แล้วก็มีคำถามอยากจะถาม ผมก็ไม่มี webboard และก็ไม่อยากจะตอบคำถามทาง msn อะไรแบบนี้เท่าไหร่ ก็เลยทำหน้า http://maccafe.wordpress.com/question-to-me/ มาแทนละกัน ดูตรง shotcut ก็ได้ครับ ทำ link ไว้ให้แล้ว

มีคำถามอะไร ที่เกี่ยวกับเขียนโปรแกรม หรืออาจจะไม่เกียว ก็จะได้ไปถามหน้านั้นเลย ง่ายๆว่า โพสมันลงไปที่หน้านั้นนั่นเหละ ถ้าผมตอบได้ก็จะตอบน่ะครับ แต่อาจจะช้านิดหนึง

จริงๆผมก็คิดไว้น่ะว่า จะทำเป็นเวปเลยดีไม๊ แต่ก็กลัวว่าจะดูแลไม่ไหว - -*

อีกอย่างคิดชื่อ โดเมน ไม่ออกว่าจะชื่อว่าอะไรดี

แต่ถ้าจะทำเมื่อไหร่่ ผมจะบอกอีกทีนะครับ

เดือนหน้าเริ่ม cocoa แล้วครับ เย้ๆๆๆๆๆๆ



Ojective-C Programming - Copying Object
June 22, 2008, 11:53 pm
Filed under: Tutorial | Tags: , ,

นี่ก็น่าจะเป็นเรื่อง objective-c แบบเพียวๆเกือบๆจะสุดท้ายละ ก็เหลืออีกไม่กี่เรื่องที่ผมคิดว่าน่าจะเพียงพอสำหรับการเริ่มต้นกับ cocoa เอาละเข้าเรื่องเลยดีกว่า

โดยปกติเราเวลาที่เราประกาศตัวแปรขึ้นมาสักตัว ถ้าไม่ใช่ class ก็จะเป็น primitive type เป็นต้นว่า int , char , double การที่เราจะ copy ข้อมูลจาก ตัวแปรหนึ่งไปยังอีกตัวแปร หนึ่งนั้นทำได้ง่ายมาก เพียงแค่ใช้เครื่องหมาย = แค่นี้เองเช่นเป็นต้นว่า

int a = 10;
int b;
b = a;
b = b+10;
a = a + 15;
NSLog(@”%d %d”,a,b);

จาก code เบื้องต้นจะเห็นว่า เราได้ให้ b มีค่าเท่ากับ a และเพิ่มค่า b ด้วย 10 แ่น่นอนว่า จาก code ข้างบนนี้ ค่า a กับ b มีค่าต่างกันคือ 20 กับ 25 สรุปง่ายๆว่า เราเปลี่ยนค่า a ก็ไม่ได้มีผลกระทบอะไรกับค่า b และในทำนองเดียวกัน ถ้าเราทำการแก้ไขค่าของ b ก็ไม่ได้มีผลอะไรกับ a

แต่การประกาศ class instance นั้นถ้าเราเขียนโปรแกรมในลักษณะเหมือนๆกับ ข้างบน ดังเช่นตัวอย่างข้างล่าง

#import <Foundation/Foundation.h>
int main()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableString *helloString = [[NSMutableString alloc] initWithCString:“Hello”];
NSMutableString *temp;
temp = helloString ;
[temp appendString:@" World"];
NSLog(@”%s”, [helloString UTF8String] ) ;
NSLog(@”%s”, [temp UTF8String] ) ;
[pool drain];
return 0;
}

เราได้ประกาศ instance ของ NSMutableString มา 2 ตัวคือ helloString กับ temp และเราก็ได้ให้ ค่า temp มีค่าเท่ากับ helloString นั่นก็แปลว่า temp ควรจะมีค่า เป็น Hello จากนั้น เราก็ได้เปลี่ยนแปลงค่า ของ temp โดยการต่อท้ายด้วย World และเราก็ให้พิมพ์ค่าตัวแปร helloString ออกมา  แต่ผลปรากฎว่า มันกลับพิมพ์คำว่า Hello World ออกมา ทั้งๆที่เราก็ไม่ได้ไปทำการแก้ไขค่าใน ตัวแปร helloString เลยสักนิด

เพราะอะไรละ ทำไมถึงเป็นแบบนี้ ?

เพราะว่า การประกาศ class instance นั้นเป็นการประกาศ pointer ของ class นั้นๆ ฉนั้นการที่เขียน code ว่า

temp = helloString

ก็เป็นการบอกว่า ให้ temp นั้นชี้ไปยังตำแหน่ง memory เดียวกันกับ helloString ฉนั้นแล้วเมื่อมันเป็น ตำแหน่ง memory เดียวกัน ถ้าหากเราทำการแก้ไข temp ก็แปลได้ว่า helloString ก็ต้องเปลี่ยนไปด้วย

เหมือนในภาษา c/c++ถ้าดู code ต่อไปนี้

char helloString[64] = “Hello World”;
char temp[64];
temp = helloString;

มันก็แปลได้ว่า เราให้ temp ชี้ไปที่ helloString ไม่ได้เป็นการ copy ค่า ถ้าหากเราจะ ให้ค่า temp เป็น Hello World เหมือนกับ helloString เราต้องใช้ ฟังชั่นที่ชื่อว่า strcpy ทำการ copy string ถ้าเป็นภาษา c/c++ อาจจะเขียนได้แบบนี้

strcpy(temp, helloString);

ปล. ใครที่ยังไม่เข้าใจเรื่อง pointer ให้ไปอ่านเพิ่มเติมน่ะครับ เดี๋ยวจะงง
http://www.vcharkarn.com/vlesson/showlesson.php?lessonid=1&pageid=7

แล้วเราจะ copy มันได้ยังไง ?

ใน Foundation class นั้นจะมี method ที่ชื่อว่า copy และ mutableCopy เพื่อให้เราสามารถ clone ค่าจาก instance หนึ่งไปยังอีก instance หนึ่งได้ และสอง method นี้ต่างกันกันตรงที่ว่า ถ้าเป็นหากเราต้องการจะคัดลอกไปแล้วให้มันแก้ไขได้ ก็ต้องใช้ mutableCopy ( สำหรับ mutable object นั้นก็ควรจะใช้ mutableCopy )

โอเคพอเข้าใจแล้วงั้นมาดูกันว่าจากข้างบนเราจะเปลี่ยนให้ temp มันเท่ากับ helloString ได้ยังไง

#import <Foundation/Foundation.h>
int main()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableString *helloString = [[NSMutableString alloc] initWithCString:“Hello”];
NSMutableString *temp;

[temp mutableCopy:helloString] ;
[temp appendString:@" World"];

NSLog(@”%s”, [helloString UTF8String] ) ;
NSLog(@”%s”, [temp UTF8String] ) ;

[pool drain];
return 0;
}

ถ้าเรา compile และ run ดูจะเห็นว่าผลลัพธ์ที่ได้จะออกมาเป็น

Hello
HelloWorld

ซึ่งจะต่างจากโปรแกรมแรกที่เราเขียน เพราะว่า เราทำการ copy ค่าจาก helloSting มาให้ยัง temp ( การ copy นี้หมายถึงการคัดลอก memory ) นั่นก็แปลว่าค่าของตัวแปรทั้งสองอันนี้แยกจากกัน ฉนั้นถ้าเราแก้ไขตัวแปร temp ก็ไม่ได้เกี่ยวอะไรกับ helloString

Shallow - Deep

อย่างที่บอกไปแล้วว่า instance นั้นคือ pointer ดีๆนี่เอง ลองพิจารณา code ข้างล่างนี้

#import <Foundation/Foundation.h>
int main()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableString *helloString = [[NSMutableString alloc] initWithCString:“Hello”];
NSMutableArray *arrayOne = [[NSMutableArray alloc] init];
NSMutableArray *arrayTwo;
[arrayOne addObject:helloString];
arrayTwo = [arrayOne mutableCopy] ;

[[arrayTwo objectAtIndex:0] appendString:@” World”];
NSLog(@”%s”, [[arrayOne objectAtIndex:0] UTF8String] ) ;
[pool drain];
return 0;
}

จากโปรแกรมข้างบน เราเริ่มด้วยการประกาศตัวแปรมาทั้ง 3 ตัวคือ arrayOne arrayTwo และ helloString หลังจากนั้น เราก็ได้เอาตัวแปร helloString ไปไว้ที่ arrayOne แล้วหลังจากนั้นก็ arrayTwo ก็ได้ copy arrayOne

สรุปว่า ตอนนี้ arrayOne มี member 1 ตัวคือ helloString ส่วน arrayTwo ก็มี member 1 ตัวเหมือนกันเพราะว่าไปก๊อปจาก arrayOne มา

หลังจากนั้นเราได้ทำการแก้ไข ค่าของ member ใน arrayTwo โดยเพิ่มคำว่า World เข้าไป

สุดท้ายเราพิมพ์ค่าของ arrayOne ออกมาร แต่ผลที่ได้คือ มันพิมพ์คำว่า Hello World !!!!
อ้าวทำไมมันเป็นแบบนี้ละ ทั้งๆที่เราแก้ไขตัวแปร ใน arrayTwo แล้วมันเกี่ยวอะไรกับ arrayOne ?

เพราะว่า … จริงอยู่ครับว่า arrayTwo นั้นก๊อปปี้ arrayOne มา นั่นก็แปรได้ว่ามันใช้ memory คนละส่วนกันแล้วดังนั้นมันก็ควรจะไม่เกี่ยวกัน ก็ถูกต้องแล้วละครับ ว่ามันไม่ได้เกียวกันการแก้ไข member ใน arrayOne ก็ไม่ได้เกียวกับ arrayTwo

แต่เผอิญว่า ตัวแปร ที่ arrayOne นั้นเก็บไว้มันเป็น pointer ที่ชี้ไปยัง helloString นั่นก็แปลได้ง่ายๆว่า member ใน array นั้นไม่ได้ถูก clone มาด้วย เป็นแค่การ copy reference มาแค่นั้น ฉนั้นการแก้ไข ตัวแปรใน arrayOne ย่อมมีผลกระทบต่อ arrayTwo สิ่งที่มันเป็นลักษณะ นี้เรียกว่า shallow copy

แล้วจะทำยังไงให้มันแยกขาดจากกันเลย ?

คำตอบคือ เราต้อง ทำเองครับ เพราะว่ามันไม่ได้ทำให้เรา แต่จะทำยังไงละ ?

Copying Class Instance

จริงอยู่ว่าเราสามารถใช้ copy , mutableCopy ได้แต่ถ้าหากเป็น class ที่เราเขียนขึ้นมาเองนั้นไม่สามารถทำได้ เราต้องเขียนเองเหมือนกัน

สรุปว่าตอนนี้ก็มีตัวอย่างที่เราต้องทำเอง ถึง 2 เคสด้วยกัน วิธีการก็ไม่ได้ยากเย็นอะไรนัก เราเพียงแค่ implement interface <NSCopy> หรือ <NSMutableCopy> เท่านั้นเอง มาดูกันเลยดีกว่า ว่ามันหน้าตาเป็นยังไง

#import <Foundation/Foundation.h>
@interface MyClass : NSObject <NSCopying>
{
 int m_number;
}
-(void) SetValue: (int) num;
-(int) GetValue;
@end
@implementation MyClass
-(void) SetValue: (int) num
{
 m_number = num;
}
-(int) GetValue
{
return m_number;
}
-(id) copyWithZone: (NSZone*) zone
{
 MyClass *temp = [[MyClass allocWithZone:zone] init];
 [temp SetValue: m_number];
 return temp;
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MyClass *myclass_A = [[MyClass alloc] init];
MyClass *myclass_B;
[myclass_A SetValue:9];
myclass_B = [myclass_A copy];

NSLog(@”%d”,[myclass_B GetValue] );
[pool drain];
return 0;
}

ก็ดูจาก code ข้างบนจะเห็นว่า ตอนที่ประกาศ class จะมีส่วนเพิ่มเติมเข้ามาคือ <NSCopying> เมื่อเรามี interface NSCopy แล้วสิ่งที่ต้องทำต่อมาก็คือ implement ส่วนของ method ที่มีชื่อว่า -(id) copyWithZone: (NSZone*) zone แล้วภายใน method ก็ประกาศตัวแปร และก็ copy ค่าต่างๆมาให้ยัง object ใหม่ที่ทำการประกาศ เพียงเท่านี้ก็เสร็จ แล้วครับ

ลอง compile และ run ดูจะเห็นว่า myclass_B นั้นมีค่าเหมือนกับ myclass_A ทุกอย่าง

งงตรงไหน ติชม คอมเม้นกันมาได้นะครับ



Ojective-C Programming - Thread II
June 16, 2008, 8:44 pm
Filed under: Tutorial | Tags: , ,

หลังจากเขียน Thread พอเป็นแล้วก็ยังมีเรื่องเกี่ยวกับ Thread ที่ต้องรู้อีก อยู่อย่างหนึ่งก็คือ การ Synchronizes ระหว่าง Thread

อย่างที่บอกไปแล้ว ว่าการเขียนโปรแกรมโดยการใช้ Thread นั้นมีข้อดีมากมาย แต่ก็มีข้อเสียเหมือนกัน และหนึ่งในข้อเสียนั้นก็คือว่า การเขียนโปรแกรมแบบที่มี thread นั้นทำให้โปรแกรมของเราซับซ้อนมากขึ้น และทำลำบากต่อการจัดการข้อมูลที่มีการใช้งานร่วมกันระหว่าง thread เช่นเป็นต้นว่า

ถ้าเกิดโปรแกรมที่เราเขียนขึ้นมีหลายๆ Thread โดยแต่ละ thread นั้นมีการแชร์ข้อมูลร่วมกัน ถ้าหากเราไม่ได้เขียนโปรแกรมให้มันมีการควบคุมการทำงานของแต่ละ thread อาจจะเกิดเหตการณ์แบบนี้ได้

สมมติว่า โปรแกรม ของเรามี 2 thread ที่มีการใช้ตัวแปรร่วมกันคือ Money และแต่ละ thread นั้นก็จะทำการอ่านค่า Money และเขียนผลลัพธ์ที่ได้จากการคำนวนใหม่ลงไป

  1. Thread A : อ่าน Money ได้มีค่าเป็น 10$ และระหว่างการคำนวนนี้ ใช้เวลาประมาณ 10 นาโนวินาที
  2. และระหว่างที่ A กำลังคำนวนอยู่นั้น Thread B ก็ได้อ่านค่า Money เหมือนกัน ได้ค่า 10$ เหมือนกัน แต่ใช้เวลาในการคำนวนเพียงแค่ 5 นาโนวินาที
  3. เนื่องจาก ว่า B นั้นทำงานเสร็จก่อน A ถึง 5 นาโนวินาที. Thread B จึงทำการ เขียนค่า Money เข้าไปใหม่เป็น 30$
  4. เมื่อ A ทำงานเสร็จ A ก็เลยเขียนค่า Money ที่ได้จากการคำนวนใหม่เป็น 15$

**** จะเห็นว่าค่าผลลัพธ์ที่ได้นั้น มันเกิดการ เขียนทับกันขึ้นมา ลองจินตนาการว่า สมมติว่า มี คนสองคนทำการฝากเงิน ในเวลาพร้อมๆกัน เข้าบัญชีเดียวกัน ขณะที่นาย A กำลังฝากเงินต้องใช้เวลาในการประมวลเสร็จใช้เวลา 10 วินาทีและในระหว่างนี้ นาย B ก็ฝากเงินมาเหมือนกัน แต่ใช้เวลา 5 วินาที ถ้าหากเราไม่มีการจัดการตรงนี้ นั่นก็แปรว่า เมื่อข้อมูลในบัญชี update จากการฝากเงินของ B ก็จะถูกเขียนทับด้วย ข้อมูลใหม่ที่นาย A ได้ฝากเข้ามา นันก็แปลว่า ข้อมูลเงินฝากนั้นผิดพลาด สิ่งที่ควรจะเป็นก็คือ ต้องรอให้ A ทำงาน เสร็จก่อน แล้ว B จึงอ่านข้อมูล ****

ลองมาเขียนโปรแกรมสักโปรแกรม โดยโปรแกรมนี้มี 2 Thread โดยที่
thread เป็นการเพ่ิมจำนวน member ใน array, ส่วนอีก thread นั้นทำหน้าที่ดึงข้อมูลจาก array แล้วทำการเปลี่ยนแปลงค่า

ลองดูโปรแกรม ข้างล่างนี้

#import <Foundation/Foundation.h>
// MyArray Class
@interface MyArray : NSObject
{
    NSMutableArray* m_array;
}
- (id) init;
- (void) dealloc;
- (void) AddMember: (NSString*) text;
- (void) AddMoreText: (NSString*) text;
- (void) PrintAllMember;
@end

@implementation MyArray
-(id) init
{
    [super init];
    m_array = [[NSMutableArray alloc] init];
    return self;
}
-(void) dealloc
{
    [m_array release];
    [super dealloc];
}
- (void) PrintAllMember
{
    int total = [m_array count];
    for( int i = 0 ; i < total ; i++)
    {
        printf(”%d %s\n”,i,[[m_array objectAtIndex:i] UTF8String]);
    }
}

// Add Member Thread Function
- (void) AddMember: (NSString*) text
{
    for( int i = 0 ; i < 100 ; i++)
    {
        [m_array addObject:[[NSMutableString alloc]initWithString:text]];
    }
}

// Add Member Thread Function
- (void) AddMoreText: (NSString*) text
{
    for( int i = 0 ; i < [m_array count] ; i++)
    {
        [[m_array objectAtIndex:i] appendString:text];
    }
}

@end

// MAIN PROGRAM
int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    MyArray *myarray = [[MyArray alloc] init];

    [NSThread detachNewThreadSelector:@selector(AddMember: )
                  toTarget:myarray  withObject:@"Hello"];
    [NSThread detachNewThreadSelector:@selector(AddMoreText: )
                  toTarget:myarray  withObject:@" World!!"];

    [NSThread sleepForTimeInterval:5];
    [myarray PrintAllMember];

    [pool drain];

    return 0;

}

และจากการ Compile & Run โปรแกรม ผลลัพธ์ที่ได้จะมีเป็นประมาณนี้

0 Hello World!!
1 hello World!!
.
.
8 Hello World!!
9 Hello World!!
10 Hello World!! World!!
11 Hello World!! World!!
12 Hello World!! World!!
13 Hello World!! World!!
14 Hello World!! World!!
15 Hello World!!
16 Hello World!!
17 Hello World!!
18 Hello
.
.
98 Hello
99 Hello

จากผลลัพธ์จะเห็นว่า เนื่องจาก Thread ทั้งสองคือ thread ที่เรียกใช้งาน AddMember ที่ทำหน้าที่เพิ่มจำนวน member ใน m_array  และ อีก thread ทำหน้าที่ AddMoreText ทำหน้าที่เรียกใช้ ตัวแปร m_array และแก้ไขค่า ในแต่ละ member ของ m_array ซึ่งสอง thread ทำงานแยกจากกันและเริ่มทำงานพร้อมกัน

ดังนั้น ในขณะที่ Thread ทั้งสองทำงานและมีการใช้งานข้อมูลร่วมกัน โดยไม่มีการ synchronize ข้อมูลระหว่างกันว่า m_array ว่าตอนนี้ข้อมูลเป็นอย่างไร ทำให้โปรแกรม นั้นทำงานผิดพลาดได้ 

วิธีการแก้ปัญหา หรือป้องกัน สิ่งที่เกิดขึ้น วิธีที่นิยมใช้ คือ การ Lock ตัวแปร กันไม่ให้ thread อื่นๆเข้าใช้จนกว่าจะใช้งานเสร็จ

NSLock

ตัวแปร NSLock นี้จะเข้ามาช่วยในการจัดการ การทำงานของแต่ละ thread โดยมันจะทำหน้าที่ lock ส่วนที่ต้องการ run ไว้ ส่วน thread อื่นๆ ก็ต้องทำการรอ จนกว่า จะมีการ unlock

การใช้งาน NSLock นั้น ก็เพียงแค่ประกาศ NSLock ขึ้นมา และเรียกใช้ lock หรือ unlock เท่านั้นเอง

จากตัวอย่าง code ข้างบน ก็แก้ไข ส่วนของ interface โดยการเพิ่มตัวแปร NSLock และในส่วนของ method ก็ทำการ เรียกใช้ lock และ unlock

@interface MyArray : NSObject
{
    NSLock *m_lock;
    NSMutableArray* m_array;
}

ส่วน Method ก็ทำการแก้ไขได้เป็น

- (void) AddMember: (NSString*) text
{
     [m_lock];
     for( int i = 0 ; i < 100 ; i++)
     {
        [m_array addObject:[[NSMutableString alloc]initWithString:text]];
     }
     [m_unlock];
}

- (void) AddMoreText: (NSString*) text
{
    [m_lock];
    for( int i = 0 ; i < [m_array count] ; i++)
    {
        [[m_array objectAtIndex:i] appendString:text];
    }
    [m_unlock];
 }

เพียงเท่านี้ก็แก้ปัญหาได้แล้ว สำหรับผลลัพธ์ ที่่ออกมาก็คือ

0 Hello World!!
1 Hello World!!
.
.
98 Hello World!!
99 Hello World!!

จะเห็นว่า จะไม่เกิดการซ้อนทับ เหมือนกับ ตัวอย่างแรก

@synchronized

ยังมีอีกวิธี ที่สามารถทำการ lock ในส่วนที่ต้องการได้ ถ้าไม่ต้องการใช้ NSLock เราเพียงแค่เขียน code ที่ต้องการจะ lock ไว้ภายในส่วนของ @synchronized { } ก็ทำได้เหมือนกัน

เป็นต้นว่า
 

- (void) AddMoreText: (NSString*) text
{
    @synchronized(self)
    {
         for( int i = 0 ; i < [m_array count] ; i++)
         {
             [[m_array objectAtIndex:i] appendString:text];
         }
    }
}

ก็ติดปัญหาอะไร ถามได้น่ะครับ



Ojective-C Programming - Thread
June 9, 2008, 2:31 am
Filed under: Tutorial | Tags: , , ,

ก็ยังคงต่อเนื่องด้วย Objective-C เหมือนเดิม ว่าจะขึ้น cocoa มา 3 รอบแล้วก็ยังไม่ได้ขึ้นสักที บอกตั้งแต่ iPhone SDK เพิ่งจะออกจนตอนนี้มันเป็น Beta 6 ไปละ หวังไม่โกรธกันนะครับ เอาละวันนี้เข้าเรื่องเลยดีกว่า

Thread

คืออะไร ?  ก็อธิบายได้ง่ายๆว่า มันคือส่วนย่อยๆของ Process หรือชุดคำสั่งนั่นเหละ โดยทำงานแยกจากกัน โดยปกติแล้วโปรแกรมที่เขียนขึ้นมาง่ายๆมักจะเป็นลักษณะ 1 thread หรืออาจจะเรียกได้ว่า “Single Thread” ถ้ามีหลายๆ thread ก็เรียกว่า “multithread” สำหรับโปรแกรมใหญ่ๆแล้วจะมีการใช้ thread มากกว่า 1

การใช้งาน thread มีข้อดีหลายอย่างตั้งแต่ การใช้ทรัพยาการร่วมกัน การสนับสนุนการทำงานของ multi processor และอื่นๆอีกมากมาย สำหรับใครที่ไม่เคยรู้เรื่อง thread นั้นแนะนำให้ไปอ่านเพิ่มเติม

http://www.thaiall.com/os/os04.html

http://en.wikipedia.org/wiki/Thread_(computer_science)

พอเข้าใจเบื้องต้นแล้ว เข้าสู้เนื้อหาของเราเลยดีกว่า ว่าเราจะสร้าง Thread และใช้งานมันได้อย่างไร

NSThread

ใน objective-c นั้นสามารถทำได้ตั้งแต่การเรียกใช้ thread ของ ภาษา c เช่น pthread แต่ไหนๆเราจะเขียน objective-c กันแล้ว จะไปใช้ pthread กันทำไม เพราะใน objective-c เองนั้นก็มี class ที่อำนวยความสะดวกในการสร้าง thread อยู่แล้วนั่นคือ NSThread

การสร้าง thread นั้นทำได้ อยู่ 2 วิธีคือ

  • เรียกใช้ class method ที่มีชื่อว่า detachNewThreadSelector:toTarget:withObject:
[NSThread detachNewThreadSelector:@selector(sampleMethod: ) toTarget:self withObject:nil];

การสร้าง thread แบบนี้เราไม่จำเป็นต้องประกาศ ตัวแปรอะไรเลย จะมีก็แต่ parameter ที่ต้องใส่เข้าไป  

  • สร้าง NSThread ขึ้นมาแล้วเรียก start
NSThread* myThread = [[NSThread alloc] initWithTarget:self
                               selector:@selector(myThreadMainMethod: )
                               object:nil];
[myThread start];

ส่วนแบบวิธีนี้ต่างจากอันแรกคือ เราสร้างตัวแปร NSThread ขึ้นมาแล้วก็ใส่ค่า parameter ให้กับมัน หลังจากนั้นก็เรียก start สำหรับการสร้างแบบนี้มีข้อดี ต่างจากอย่างแรกก็คือ เราสร้างไว้ก่อนแล้วค่อยเรียกให้ thread start ทีหลังได้

ก็หลังจากสร้างเป็นแล้ว มาดูการใช้งาน กันเลยดีกว่า

สมมติว่า เราจะเขียนโปรแกรม ที่เอาไว้เขียน console แบบง่ายๆกัน แต่เป็นแบบ หลายๆ thread 

#import <Foundation/Foundation.h>

//————————————–
// Console Class 
//————————————–



@interface Console : NSObject { }
- (void) PrintToConsole : (NSString*) text;
@end

@implementation Console
- (void) PrintToConsole : (NSString*) text;
{  
   for ( int i = 0 ; i < 5 ; i++ )  
   {   
        printf(“%d: “,i); 
        NSLog(text);  
   } 
} 

@end

//————————————–
// MAIN PROGRAM
//————————————–

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

Console *sampleConsole = [[Console alloc] init];
Console *helloConsole =  [[Console alloc] init];
Console *okConsole =     [[Console alloc] init]; 

NSThread *helloThread = [[NSThread alloc] initWithTarget:helloConsole 
                        selector:@selector(PrintToConsole: ) 
                        object:@”Hello”];  

[NSThread detachNewThreadSelector:@selector(PrintToConsole: )  
                                  toTarget:sampleConsole 
                                  withObject:@"Sample"];       

[NSThread detachNewThreadSelector:@selector(PrintToConsole: )  
                                  toTarget:okConsole 
                                  withObject:@"Ok"];    

NSLog(@”\nHello, World From Main thread!\n”);
[helloThread start];   

[NSThread sleepForTimeInterval:1];           
[pool drain];
return 0;
}

จากโปรแกรม ข้างบน อธิบายคร่าวๆนะครับว่า เราประกาศ  class Console ขึ้นมาโดยที่มี method  เพียงแค่ PrintToConsole โดยการทำงานของ method นี้ก็คือให้พิมพ์ข้อความ ออกมาที่ console ทั้งหมด 5 ครั้ง 

หลังจากนั้นก็ทำการประกาศ ตัวแปร Console ขึ้นมาอีก 3 โดยแต่ละ object นั้นก็ทำการพิมพ์ข้อความออกมาไม่เหมือนกันนั่นก็คือ Hello , Sample , Ok

หลังจากนั้น ก็ทำการ สร้าง Thread ขึ้นมา โดยจากตัวอย่าง ผมได้ทำการใช้วิธีการประกาศทั้ง 2 แบบคือทั้งแบบ ประกาศ ตัวแปร NSThread ขึ้นมาก่อน แล้วค่อยเรียก Start และอีกแบบก็คือไม่ต้องประกาศ ตัวแปร แต่เรียกใช้ class method ขึ้นมาเลย

ยังมีอีก 1 method ที่น่าสนใจก็คือ sleepForTimeInterval โดยฟังชั่นนี้ทำหน้าที่คือ หยุดการทำงานตามเวลาที่กำหนด สาเหตุก็เพราะว่า เนื่องจากว่า Thread นั้นทำงานแยกกัน และแต่ละ Thread อาจจะมี Thread ใดๆ ทำงานเสร็จก่อน หรือหลัง Main Program ก็ได้ ฉนั้นจึงทำการรอให้ แต่ละ Thread ทำงานเสร็จก่อน แล้วค่อยจบโปรแกรม

และหลังจาก compile และ run แล้วผลลัพธ์ที่ได้ จะได้ประมาณแบบนี้

0: 0: 2008-06-09 00:52:54.252 Thread[724:1103] Sample
1: 2008-06-09 00:52:54.253 Thread[724:1203] Ok
1: 2008-06-09 00:52:54.252 Thread[724:10b] 
Hello, World From Main thread!
0: 2008-06-09 00:52:54.258 Thread[724:1103] Sample
2: 2008-06-09 00:52:54.258 Thread[724:1203] Ok
2: 2008-06-09 00:52:54.259 Thread[724:2c03] Hello
1: 2008-06-09 00:52:54.260 Thread[724:1103] Sample
3: 2008-06-09 00:52:54.260 Thread[724:1203] Ok
3: 2008-06-09 00:52:54.261 Thread[724:2c03] Hello
2: 2008-06-09 00:52:54.262 Thread[724:1103] Sample
4: 2008-06-09 00:52:54.262 Thread[724:1203] Ok
4: 2008-06-09 00:52:54.263 Thread[724:2c03] Hello
3: 2008-06-09 00:52:54.264 Thread[724:1103] Sample
2008-06-09 00:52:54.265 Thread[724:1203] Ok
2008-06-09 00:52:54.265 Thread[724:2c03] Hello
4: 2008-06-09 00:52:54.267 Thread[724:2c03] Hello

จะเห็นว่า ลำดับ แต่อันจะไม่เรียงกัน อาจจะสลับกันไปมา ก็เนื่องจากว่า Thread แต่ละอันนั้นทำงานแยกจากกัน

 

ข้อระวังสำหรับการใช้ Thread ใน Objective-C

ใน Thread ถ้ามีการประกาศตัวแปร หรือว่าใช้งาน ลักษณะที่ต้องมีการจอง memory ต้องมี NSAutoreleasePool ด้วยเสมอ 

เช่น

- (void) PrintToConsole : NSString* text  ถ้าเราจะเปลี่ยน code การทำงานให้มันพิมพ์ออกที่หน้า console เหมือนกันแต่เราไม่อยากใช้ NSLog ก็อาจจะเขียนใหม่ได้ว่า

- (void) PrintToConsole: (NSString*) text;
{ 
   for ( int i = 0 ; i < 5 ; i++ ) 
   {  
     printf(“%d: %s “,i, [text UTF8String]);
   } 
} 

การเขียนแบบนี้เวลา run จะเกิด error น่ะครับ เพราะว่า [text UTF8String] มันจะไปจอง memory ใหม่แล้วส่งค่า char* กลับมา ฉนั้น ถ้าไม่มี NSAutoreleasePool มันจะ error

การเขียนที่ถูกต้องควรจะเป็น

- (void) PrintToConsole: (NSString*) text;
{ 
NSAutoreleasePool * threadPool = [[NSAutoreleasePool alloc] init];
  for ( int i = 0 ; i < 5 ; i++ )  
  {   
    printf(“%d: %s “,i, [text UTF8String]);
 
[threadPool drain];
}  

สำหรับ tutorial นี้จริงๆผมกะว่าจะเป็น guide ง่ายๆสำหรับคนที่รู้เรื่อง thread อยู่แล้ว ก็ถ้าใครยังไม่เข้าใจ ต้องการรู้เรื่องเกี่ยวกับ thread เพิ่มมากขึ้นก็แนะนำให้ไปอ่าน link ที่ข้างบน แล้วก็ค้นหาจาก google ก็ได้ครับ 

 

ครั้งหน้า ก็ยังอยู่กับ objective-c น่ะครับ ส่วน source สำหรับ วันนี้ก็โหลดได้ที่นี่เลย Source Download ส่วนวิธีการก็เหมือนเดิมคือ โหลดมันไปเป็น jpg นั่นเหละ แล้วก็ เปลี่ยนนามสกุลให้เป็น rar แล้วก็ใช้โปรแกรม unrarx หรือ  simplerar เปิดออกมา



Ojective-C Programming - Basic Memory Management
May 28, 2008, 3:02 am
Filed under: Tutorial | Tags: , , ,

ก็ห่างหายหน้า หายตากันไปกว่าๆ 2 อาทิตย์ที่ไม่ได้เขียน tutorial ก็ติดงานค่อนข้างวุ่นวายทีเดียว ก็พยายามปลีกเวลามาเขียนเพราะหลังๆ เข้าใจว่าหลายคนอยากจะก้าวไปยัง iPhone ใจจริงก็อยากจะขึ้น cocoa + iPhone ใจจะขาด แต่คิดไปคิดมา ยังเหลือเรื่องเกี่ยวกับ objective-c ที่เป็น Fundamental อยู่อีกหลายเรื่อง ก็เลยตัดสินใจว่าจะเขียน ให้มันครอบคลุมในส่วนที่ต้องใช้และเข้าใจก่อนไป สู่การเขียน cocoa และ iPhone เป็นลำดับ 

เอาละเข้าสู้เนื้อหากันเลยดีกว่า

Memory Management อาจจะฟังดูน่ากลัวสักหน่อยว่า เราจะต้องเข้าใจในระดับไหน แต่เอาเป็นว่าการจัดการหน่วยความจำ เนี่ยเป็นสิ่งสำคัญมากสำหรับการเขียน โปรแกรม ถ้าเป็นอย่างภาษา java หรือว่า Visual Basic  อาจจะดีหน่อยตรงที่ว่า เราไม่ต้องไปยุ่งเกี่ยวอะไรเกี่ยวกับ memory เลย อยากประกาศก็ตัวแปร ก็ประกาศ ใช้เสร็จก็ช่างมัน อะไรแบบนี้ ก็เนื่องด้วยว่าภาษาเหล่านี้ได้ทำการจัดการหน่วยความจำให้เราโดยอัตโนมัติ เราเลยไม่มีความจำเป็นต้องจัดการเอง ส่วนภาษา Objective-C  นั้นก็มีการจัดการหน่อยความจำให้เหมือนกัน มี garbage collector เช่นกัน แต่มันยืดหยุ่นกว่า ตรงที่ว่า เราสามารถจัดการเองได้ด้วย

Autorelease Pool

การจัดการเกี่ยวกับ memory อย่างแรกเลยที่ต้องรู้ และน่าจะคุ้นเคยก็คือ NSAutoReleasePool ชื่อมันอาจจะเหมือนว่า ทำให้อัตโนมัติแต่ความเป็นจริงแล้วก็ไม่ได้เป็นอย่างที่ว่า ความสำคัญของ class นี้คือ

ถ้า object ได้ส่ง message ให้ทำการ release.
ตัว object นั้นจะถูกใส่เข้าไปยัง pool เพื่อที่ว่า ถ้าเมื่อไหร่ pool ได้คืนหน่วยความจำ ( release ) ให้กับระบบ มันก็จะไปไล่คืนหน่วยความจำให้กับทุกๆ object ที่อยู่ใน pool

ถ้าเราทำการเขียนโปรแกรมด้วย Foundation Framework จะต้องมี Autorelease pool อยู่ด้วยเสมอ ( ถ้าเป็น cocoa เราไม่ต้องประกาศก็ได้ เพราะว่ามันจะมีมาให้อยู่แล้ว ) 

บางทีก็อาจจะจำเป็นที่จำต้องมีหลายๆ autorelease pool เช่นกรณีที่ว่า โปรแกรม loop ไปนานมากๆ แบบนี้ก็ถ้ามีหลายๆ pool ค่อยๆทยอย release ก็อาจจะดีกว่า เช่นว่า

while (true)
{
      NSAutoreleasePool *pool = [[ NSAutoreleasePool alloc] init];
      //  Some code allocate many memory ………
      [pool release];
}

Retain & Release

เราต้องทำความเข้าใจกันก่อนว่า Object ในโปรแกรมสัก 1 ตัว อาจจะมี Object อื่นๆทำการใช้งานมันอยู่ จะเกิดอะไรเกิดขึ้นถ้าเผื่อว่า ObjectA ต้องการจะเรียกใช้ ObjectB แต่กลายเป็นว่า ObjectB ได้ release ไปแล้ว. แต่โดยความจริงแล้วส่วนมากปัญหามักจะเกิดจากการไม่คืนหน่วยความจำซะมากกว่า.

ในภาษา Objective-C นั้นถ้าหาก Object ใดๆที่มีการถูกใช้งานโดย Object อื่นๆจะไม่สามารถ free memory ได้ จนกว่าจะไม่มี Object ใดๆใช้มันอีก. เอาละปัญหาก็เกิดขึ้นอีก ว่าจะทำอย่างไรให้รู้ว่าไม่มี Object ไหนใช้ ? 

ปัญหานี้ก็แก้ได้โดยการบอกกับ object ตัวนั้นให้มันนับว่ามีใครอ้างถึงมันมากเท่าไหร่ สำหรับ function ที่เอาไว้บอกว่า เราได้ทำการใช้มัน อยู่ก็คือ retain . 

retain นั้นจะไปเพิ่มจำนวนของ counter ให้กับ object นั้นว่ามีการอ้างถึง  
ในทางกลับกัน release ก็จะไปลดจำนวนการอ้างอิง

releaseCount เอาไว้บอกจำนวนของ object ที่มาใช้งานตัวมันอยู่

มาดูตัวอย่างง่ายกันดีกว่า

 
#import <Foundation/Foundation.h>
#import <Foundation/NSArray.h>
@interface SampleClass : NSObject
{
}
@end
@implementation SampleClass
@end
int main (int argc, const char * argv[]) 
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSMutableArray *array = [NSMutableArray array];
    SampleClass *objectA = [SampleClass alloc];
    SampleClass *objectB;
    printf(“ObjectA retain count = %d\n”, [objectA retainCount]);

    // Add objectA to array
    [array addObject:objectA];
    printf(“objectA after add to Array\n”);
    printf(“retain count = %d\n”, [objectA retainCount]);

    // objectB refer to objectA
    objectB = objectA;
    printf(“\nobjectB after refer to objectA\n”);
    printf(“retain count = %d\n”, [objectA retainCount]);

      // calling retain
    [objectA retain];
    printf(“\nobjectA after retain\n”);
    printf(retain count = %d\n”, [objectA retainCount]);

    // release
    [objectA release];
    printf(“\nobjectA after release\n”);
    printf(“retain count = %d\n”, [objectA retainCount]);

    // remove from array
    [array removeLastObject];
    printf(“\nobjectA after remove from array\n”);
    printf(“retain count = %d\n”, [objectA retainCount]);
    
    [pool release];
    return 0;
} 

ก็จากตัวอย่าง ข้างบนอธิบายคร่าวๆก่อนแล้วกัน คือ เราทำการประกาศ ObjectA ขึ้นมาแล้วก็ ประกาศ array มา อีกตัว  

ในครั้งแรกหลังจากประกาศเราก็ทำการ นับค่าตัวที่อ้างอิงก็จะได้ผลลัพธ์เป็น 1 เพราะมีแต่ตัวเองใช้ 

หลังจากนั้น ก็เอา ObjectA ใส่เข้าไปยัง array แล้วนับใหม่ก็ จะได้เป็น 2 เพราะ array ได้อ้างอิงถึง objectA อีกตัว

และก็เรียกใช้ retain เฉยๆ ก็จะเพิ่มเป็น 3

หลังจากนั้นก็เรียก release จำนวนก็ลดลงเหลือ 2 และสุดท้าย

ก็ลบ ObjectA ออกจาก array นับใหม่ก็จะได้ 1 เหมือนเดิม

ผลลัพธ์ที่ได้ก็จะมีหน้าตาประมาณนี้

objectA retain count = 1

objectA after add to Array
retain count = 2

 

objectB after refer to objectA
retain count = 2

 

objectA after retain
retain count = 3

 

objectA after release
retain count = 2

 

objectA after remove from array
retain count = 1

ก็เป็นว่าน่าจะพอเข้าใจเบื้องต้นเกี่ยวกับ memory management เพิ่มบ้างอ่ะน่ะ 


Talk: WWDC 2008
May 19, 2008, 11:17 am
Filed under: Talk | Tags:

คือช่วงนี้หายหน้าหายตาไป เพราะว่าติดงานเลยไม่ค่อยได้เขียน blog เท่าไหร่ แต่ผมจะพยายามเขียน cocoa ให้มันเสร็จโดยเร็ว ( เนื้อหามันเยอะมากเลย ) เอาละ พูดถึง WWDC 2008 มันคืองาน World Wide Develop Conference ก็เป็นงานประชุมสัมนาของนักพัฒนา software ให้ักับ apple นั่นเหละ และงานที่จะถึงนี้งานมันคงเน้นไปที่ iPhone เป็นหลัก เพราะแน่นอนว่าเค้าจะออก Firmware version2 มาให้ได้ใช้แน่นอน และยังอาจจะมีการเปิดตัวของ iPhone 3G กันในงาน

งานนี้ผมเกือบได้ไปละ แต่ว่าก็ไม่ได้ไป เพราะช่วงที่บอสไปต่างประเ้ทศกับเพื่อนผม เค้าจะได้มี meeting กับ พวก apple engineer ผมเลยบอกว่า ช่วยขอบัตร ให้ด้วยได้ไหม บอสเค้าก็รับปาก แต่ผลกลายเป็นว่า ได้เจอกับ apple น่ันเหละ แต่ว่า กลายเป็นการกินข้าวเฉยๆ คือไม่ได้อะไรเท่าไหร่ เรื่องงาน WWDC ก็เลยไม่ได้พูดถึง ก็โอเคว่าไม่ได้บัตฟรี ผมก็คิดว่าจะไปขอบอสว่าอยากไป ซึ่งก็คิดว่าบอสก็คงจะให้ เพราะผมมีโปรเจคต้องเขียนโปรแกรมโปรแกรมให้กับ iPhone อยู่ด้วย แต่เนื่องจากว่า ความสำคัญของงานผมตอนนี้มันคือ mac ผมเลยลังเลใจ พอจะไปขอจริงๆ ก็กลายเป็นว่า บัตร WWDC มันขายหมดแล้ว โอ้วววว ไม่น่าเชื่อว่ามันจะขายหมด ( เค้าบอกว่าเป็นครั้งแรกเลยที่มันขายหมด ) และผมก็เชื่อว่า คนส่วนมากก็น่าจะเข้า iPhone Session เยอะแน่ๆเลย ก็น่าเสียดายเนอะ ที่ตัดสินใจช้าไปนิด ก็เอาไว้ปีหน้าก็แล้วกัน



XCode Video Tutorial
April 28, 2008, 5:11 pm
Filed under: Tutorial | Tags: ,

ก็วันนี้ผม upload tutorial เกี่ยวกับการใช้งาน xcode ในเบื้องต้นสำหรับคนที่ยังไม่เคยใช้ ก็ไม่รู้ว่าไฟล์มันใหญ่ไปหรือเปล่า ก็ลองดูกันก่อนละกัน หลังๆจากนี้จะพยายามทำเป็น vdo เลยอาจจะง่ายกว่าก็ได้

ในอาทิตย์หน้า น่าจะเข้าสู่ cocoa ได้แล้วน่ะ ถ้าผมไม่ติดงานอะไรเร่งด่วน

ปล. มีคำถาม คำแนะนำ ติชม ก็บอกได้น่ะครับ อยากให้เพิ่มอะไร
ถ้าอยากดูชัดๆก็ download แบบ .mov ไปดูก็ได้น่ะครับ ขอไว้อีกอย่างว่ากรุณาอย่านำไฟล์ไปลง youtube น่ะครับ

XCode Tutorial ( 640×480 , 17 Mb. )



iPhone Programming - Road map
April 23, 2008, 7:13 pm
Filed under: Talk | Tags: , , , ,

หลังจากที่คิดอยู่นานว่าจะเริ่มอย่างไรดีกับ iPhone SDK และก็คงคิดว่ามีหลายๆคนอยากจะเขียนโปรแกรม สำหรับ iPhone แต่ก็ยังไม่รู้เลยว่า มันจะเขียนยังไง สำหรับบทความนี้ เป้าหมายหลักของผมคืออธิบายภาพรวมของการเขียนโปรแกรมบน iPhone ให้เข้าใจกันเบื้องต้นก่อนว่า ก่อนที่คุณจะเขียนโปรแกรมบน iPhone นั้นสิ่งที่ต้องรู้เบื้องต้นกันก่อน คืออะไร

Language

การเขียนโปรแกรมบน iPhone นั้นแบ่งภาษาที่ใช้ในการเขียนหลักๆเป็น 2 ภาษา ( จริงๆมีอีกภาษาคือ objective-c++)

  • Objective C
  • C/C++

ภาษาอื่นๆหมดสิทธ์ ( อาจจะมีภาษาอื่นในอนาคต แต่ในตอนนี้มีแค่ 2 ภาษานี้เท่านั้น ) ถ้าหากเขียน java หรือว่า C# หรือ Visual Basic มาก่อน ก็คงต้องเลือกเอาละครับว่า ต้องเรียนรู้ภาษาใดภาษาหนึ่งเพิ่มเติมแน่นอน

แล้วควรจะเลือกภาษาใด ?
ผมก็ไม่อาจจะบอกได้แน่ชัดว่า ควรเลือกภาษาใดถึงจะเหมาะสม แต่แนะนำข้อดีของแต่ละอันดีกว่าว่ามันมีดีต่างกันยังไง

C/C++

ข้อดีของภาษานี้ที่ผมเห็นว่ามันดีที่สุดคือ การหาหนังสือเกี่ยวกับการเขียนโปรแกรมภาษา C/C++ ง่ายมาก หนังสือภาษาไทยก็มี เดินเข้าร้านหนังสือก็เจอแล้ว ( แต่ไม่ค่อยมีหนังสือภาษาไทยที่ลงลึกการเขียนโปรแกรมด้วย C/C++ ) และไม่ใช่แค่หนังสือแต่รวมไปถึง source code, library, tutorial และมี community ที่ใหญ่มาก และมันเป็นภาษาที่นิยมแพร่หลายและเก่าแก่ และในปัจจุบันก็ยังนิยมใช้อยู่

ข้อเสียที่ผมคิดว่ามันน่าจะเป็นเรื่องของ การเขียนโปรแกรมด้วยภาษา c/c++ ให้ได้ดีนั้นค่อนข้างยาก ไม่ใช่ว่าภาษามันไม่ดี แต่เป็นเพราะว่าตัวภาษามันสามารถลงลึกถึงขั้นจัดการหน่วยความจำได้ ( มันมีสิ่งที่เรียกว่า pointer ) และนี่ก็เป็นดาบสองคม เพราะถ้าเขียนโปรแกรมให้มันจัดการหน่วยความจำไม่ดี โปรแกรมเราก็ทำงานได้ประสิทธิภาพที่แย่มากๆ และหนำซ้ำอาจจะไปทำให้ระบบรวนอีก ( ถ้าในภาษา java หรืออื่นๆนั้น แทบจะไม่ต้องไปทำเขียนอะไรเกี่ยวกับหน่วยความจำเลย เพราะมันมี Garbage collector เอาไว้จัดการหน่วยความจำให้เรียบร้อย )

Objective-C

ข้อดีของมันคือ ภาษา objective-c มันค่อนข้างเรียนรู้ง่าย ไม่ซับซ้อน ( เค้าบอกว่ามันเป็นเหมือนภาษา C ผสมกับ smalltalk ) และมี Framework, Lib ให้ใช้เยอะมาก ภาษามีความยืนหยุ่นสูง และเนื่องจากว่ามันเป็น small super set of C นั่นก็แปลว่า เราสามารถใช้ lib หรือ code ของ C ได้ ( ไม่ใช่ C++ น่ะ ) และตัวภาษา ก็ยังอนุญาติให้เราเข้าไปทำงานจัดการหน่วยความจำได้เหมือนกันแต่ก็ไม่เท่ากับ c/c++ และมันยังมี Garbage collector ในกรณีที่ไม่ต้องการจัดการหน่วยความจำเอง และข้อดีที่สุดคือ การเขียน application บน mac นั้น ถ้าเขียนด้วยภาษา objective-c คือมันมี interface builder ทำให้เราออกแบบหน้าตาโปรแกรมและเขียน โปรแกรมได้ง่ายขึ้นกว่า c/c++ เยอะมาก

ข้อเสียคือ หนังสือให้อ่านน้อยมาก *** ย้ำว่าน้อยมาก *** หนังสือภาษาไทยไม่มีให้อ่าน และคนเขียนโปรแกรมด้วย objective-c นี้ก็น้อยมาก ( บางคนอาจะไม่เคยได้ยินชื่อภาษามาก่อนด้วยซ้ำไป ) จากสิ่งนี้ทำให้ การหา source , tutorial นั้นยากตามไปด้วย แต่ผมคิดว่าหลังจาก ที่ apple ปล่อย iphone sdk ออกมาแล้วคิดว่า หนังสือหรือ community และ resource ต่างๆน่าจะมีเยอะกว่านี้

ส่วนเรื่องอื่นๆในรายละเีอียดของภาษาว่าแตกต่างกันอย่างไรในแบบลึกๆ ลองไปดูเพิ่มเิติมได้ที่

http://en.wikipedia.org/wiki/Comparison_of_programming_languages

Framework

และสืบเนื่องจากที่ว่า การเขียนโปรแกรมบน iPhone นั้นแบ่งออกเป็น 2 ภาษาทำให้ apple ออกแบบ Framework มาเป็น 2 อย่างคือ

  • Cocoa
  • Carbon

สองอย่างนี้ มันสามารถทำงานร่วมกันได้ในบางส่วน แต่โดยปกติแล้วจะแยกจากกัน ถ้าเขียนโปรแกรมด้วยภาษา objective-c นั้นเราจะใช้ Cocoa ส่วน C/C++ นั้นจะใช้ Carbon

ดังนั้นถ้าหากเลือกได้ว่าจะเขียน ด้วยภาษาใดแล้วมันก็เหมือนเป็นการบังคับไปเลยว่า เราต้องใช้ Framework แบบไหน แต่ข้อดีของมันก็คือว่า ทั้ง Cocoa และ Carbon ออกแบบมาใกล้เคียงกันมาก ยกตัวอย่าง NSView ( เป็นคลาสหนึ่งใน Cocoa ) ในส่วนของ Carbon ก็จะมีคลาสที่คล้ายๆกันคือ HIView และมี method ที่คล้ายๆกันอีกต่างหาก ( แต่ concept การทำงานบางอย่างมันจะไม่เหมือนกันซะทีเดียว )

Tools

เครื่องมือที่ใช้ในการเขียนโปรแกรมสำหรับ iPhone นั้นมีอย่างเดียวคือ XCode ซึ่งมันจะประกอบไปด้วยส่วนย่อยๆอีก หลายอัน เช่น Simulator , Instrument

Xcode นั้นเป็นโปรแกรมที่แถมมาฟรีกับ Mac OSX โดยปกติจะอยู่ในแผ่นที่แถมมาตอนซื้อเครื่องในแผ่นที่ 2 ถ้าไม่มีก็โหลดได้จากเวปของ apple แต่ต้องสมัครเป็นสมาชิก adc member ก่อน และในตอนนี้ XCode ก็ออกมาเป็น version 3.1 แล้ว

หลังจากลง iPhone SDK ไปแล้ว XCode เราจะ upgrade เป็น 3.1อยู่แล้ว

เฉพาะสำหรับ Objective-C จะมีเครื่องมือที่เรียกว่า Interface Builder เอาไว้ออกแบบหน้าตาโปรแกรม ตั้งแต่ ปุ่มกด สกอบาร์ และอื่นๆมากมาย ในขณะที่ C/C++ ต้องเขียน code ออกแบบหน้าตาโปรแกรมเอง

Ready ?

หลังจากรู้คร่าวๆไปแล้ว ว่าการที่เราจะเขียนโปรแกรมบน iPhone นั้นมีขั้นตอน และต้องรู้อะไรมาบ้าง แน่นอนว่าบางคนอาจจะต้องเรียนรู้ทุกอย่างใหม่หมด ตั้งแต่ ภาษา เครื่องมือ ในการเขียนโปรแกรม แต่อย่าไปกลัว เมื่อก่อนผมเองก็ยังไม่เคยเขียนโปรแกรมบน mac มาก่อนเลย ก็ยังอ่านและทดลองเองหมด ฉนั้นไม่ยากเกินความสามารถแน่ๆ

สรุปว่า ถ้าอยากเขียนโปรแกรมบน iPhone สิ่งที่จะต้องรู้ก็คือ

  • ภาษา c/c++ หรือ objective-c
  • cocoa หรือ carbon
  • XCode

และในต่อไป ผมจะทดลองเขียน cocoa กันก่อนแล้วถึงจะไปต่อยอด iPhone ไม่นานเกินรอ ( และแน่นอนว่ารวมทั้ง Carbon ด้วย )



Starting XCode
April 17, 2008, 6:33 pm
Filed under: Tutorial | Tags: ,

Xcode

คือเครื่องมือ ( IDE ) ในการเขียนโปรแกรมบน mac ความเป็นจริงแล้วเราไม่จำเป็นต้องใช้ xcode เขียนโปรแกรมก็ได้ ใช้ text editor ธรรมดาก็ได้ แต่มันไม่สะดวกเท่ากับการใช้เครื่องมือ ถ้าจะเปรียบเทียบก็เหมือนกับการใช้ Visual Studio เขียนโปรแกรมบน Windows นั่นเหละ สำหรับผมแล้ว xcode นั้นเป็นเครื่องมือที่ดีที่สุดในการเขียนโปรแกรมบน mac เพราะมันรวมแทบจะทุกอย่างไว้ในตัวมันเอง ตั้งแต่ text editor , debugger , source control , document และอื่น โดยปกติแล้ว xcode จะไม่ได้ติดตั้งมาพร้อมกับ mac osx แต่มันจะมีมาให้อยู่ในแผ่น dvd/cd ที่แถมมาตอนซื้อเครื่อง ( ปกติจะมี 2 cd/dvd แล้วมันจะอยู่ในแผ่นที่ 2 ) ถ้าไม่มีติดตั้งมาในเครื่องก็ติดตั้งให้เรียบร้อย หรือถ้าใครไม่มีแผ่น ที่ว่าก็โหลดได้ที่เวปของ apple เอง

สำหรับ post นี้ก็เป็น basic guide ในการใช้งานเบื้องต้นก่อนละกันว่า มันใช้งานยังไง หลังจากที่เราติดตั้ง xcode ลงไปในเครื่องแล้ว เราจะได้ directory ที่มีชื่อว่า developer เพิ่มขึ้นมา ถ้าเข้าไปดูก็น่าจะเห็นประมาณในภาพ

และใน developer นี้จะมีทั้ง document และ sample code รวมมาให้ด้วย

หลังจากติดตั้งแล้วก็มาลองใช้งานกันเลยดีกว่า
เมื่อเริ่มเปิดโปรแกรม แล้วให้สร้างโปรเจคใหม่ขึ้นมา โดยเลือกจาก menu File/New Project หลังจากนั้นก็จะเห็นหน้าต่างเปิดขึ้นมาว่า โปรเจคที่เราต้องการจะสร้างนั้นคืออะไร ก็ในรูปจะมีโปรเจคหลายๆแบบ ตั้งแต่ iphone , cocoa , carbon , ruby และอื่นๆมากมาย

*** ถ้าใครอยากลองเขียนโปรแกรม แบบที่ผมเขียนเป็น tutorial ก็ต้องสร้างโปรเจค แบบ Command Line Utility แล้วก็เลือก Foundation Tool

หลังจากนั้นก็เลือกที่จะเซฟ เสร็จแล้วจะเห็น window หน้าตาประมาณนี้

ในแต่ละส่วนนั้นจะแยกเป็นหลักๆ 4 ส่วนคือ

  1. เป็นส่วนของ รายละเอียดของโปรเจค ว่ามีไฟล์อะไร บ้าง มี Framework ตัวไหนที่เราใช้ และอื่นๆ
  2. เป็นส่วนที่เราใช้ในการเขียน code หรือเรียกว่า editor
  3. หลังจากเขียนเสร็จ เราก็สารมารถทดสอบโปรแกรมของเราได้โดยการ build (ถ้ากด build มันจะทำการ build อย่างเดียวไม่มีการ run) และ Build and Go ( ตรงนี้หลังจาก build เสร็จมันจะ run โปรแกรมให้ด้วย หรือเราอาจจะเลือก run เองได้จาก menu )
  4. ตรงส่วนนี้เป็นการบอกว่าเราจะ compile เป็นแบบ debug หรือว่า release หรือว่าอาจจะเป็น custom build เองก็ได้ และมันจะบอกว่า target ที่เราจะ compile ( ในกรณีที่มีหลาย target )

** ในส่วนที่ 2 ถ้าเรา click ตรงหน้าบรรทัดของ editor จะมีสัญลักษณ์ ลูกศรสีฟ้าขึ้นมา มันคือ break point นั่นเอง ***

แล้วเราก็ลองทำการ Build and Go เล่นๆกัน ถ้าหากมี break point อยู่ก็จะเห็นว่า โปรแกรมเรา ทำงานมาถึงบรรทัดไหน ก็จะเห็นดังรูป

สังเกตว่า จะเห็น ส่วนปุ่มต่างๆเพิ่มเข้ามาใน editor ซึ่งจะประกอบไปด้วยส่วนต่างๆดังนี้คือ

  • Break point
  • Current Thread ( ในการณีที่เรามีหลาย thread เราสามารถเปลี่ยน thread ในการ debug ได้ )
  • Step ประกอบไปด้วยส่วนย่อยๆอีก ก็คือ continues / over / into / out
  • รูปสเปรย์ คือ debugger ถ้ากดเข้าไปแล้วจะเห็น หน้าต่าง debugger ดังรูปข้างล่าง
  • debug console ตรงนี้เป็นหน้าต่าง console ของโปรแกรม คือเวลาเราใช้ คำสั่งพวก NSLog มันจะแสดงผลมายัง debug console นั่นเอง


( Debugger window)

ในหน้าต่าง debugger นี้เราสามารถดูค่าของตัวแปร ได้จากฝั่งทางด้านขวามือ และปุ่มต่างๆด้านบนนั้นก็จะมีคล้ายๆกับที่อธิบายไปแล้วนั่นคือ step ต่างๆ แล้วก็มี Deactivate /Active เอาไว้เพื่อทำการใช้หรือไม่ใช้ debugger และ stop เพื่อหยุดการทำงานของโปรแกรม

( Console window )

หน้าต่างนี้เป็นส่วนที่ output ที่เราเขียนออก console จะมาโผล่ หน้าต่างนี้ ( คำสั่งจำพวก printf , std::cout , NSLog ) ในส่วนของกรอบสี แดง ที่ทำไว้คือ ผลลัพธ์ของ การ run โปรแกรม จากตัวอย่าง ก็จะเห็นว่า มี Hello, World ! ออกมา

apple เองมี manual การใช้งาน xcode

http://developer.apple.com/documentation/DeveloperTools/Conceptual/XcodeUserGuide/Contents/Resources/en.lproj/00_00_intro/chapter_1_section_1.html

ก็ละเอียดเหมือนกัน ลองเข้าไปอ่านเพิ่มเติมได้ครับ มีประโยชน์มากทีเดียว

ปล. Xcode ที่ใช้เป็นตัวอย่างนี้คือ Xcode 3.1 และใช้งานบน Leopard ถ้าใครใช้ tiger อาจจะหน้าตาไม่เหมือนกัน หรือว่าใช้ xcode version 2.4 หรือ 3.0 ก็อาจจะไม่เหมือน แต่ก็คล้ายๆกัน

มีคำถามอะไรหรือ comment ยินดีน่ะ ผมจะได้รู้ว่าเขียนๆมาเนี่ยดีหรือไม่ดี จะได้เอาไปปรับปรุง



Ojective-C Programming - File Management II
April 17, 2008, 3:34 pm
Filed under: Tutorial | Tags: , , ,

ก็ช่วงนี้กำลังว่างหลังจาก โปรเจคของผมก็ได้เสร็จไปแล้วส่วนหนึ่ง กำลังรอเหมือนกันว่า ปีนี้จะมีโอกาสได้ไป WWDC กับเค้าบ้างหรือเปล่า ถ้าได้ไปก็คงจะดีเพราะเท่าที่ดูๆคิดว่า จุดใหญ่ๆของปีนี้น่าจะเป็น iphone นี่เหละ

ก็เขียน tutorial มาหลายๆเรื่องจนถึงเกือบจะสุดท้ายละ ก็น่าจะทำให้ใครหลายๆคนไปต่อยอดอ่าน cocoa ได้สบายๆหรือว่าเป็นจุดเริ่มในการเขียนโปรแกรมบน mac มั่งละ

สำหรับวันนี้ก็ต่อเรื่อง ของ File Managerment กันเลยเพราะว่าครั้งก่อนเป็นแค่การ ใช้งาน file เช่นการ copy file อะไรแบบนี้ แต่วันนี้เราจะมารู้จัก class ที่เกี่ยวกับ file เพิ่มเติมนั่นก็คือ NSData

NSData

ปกติแล้ว class ที่เอาไว้สำหรับจัดการ file ก็คือ NSFileManager  แต่ถ้าเราต้องการที่จะเขียนข้อมูลลง file หรืออ่านข้อมูลจาก file นั้นเราจะใช้ NSData เพื่อทำการอ่านและเขียนลง buffer เพื่อที่จะให้ NSFileManager จัดการเขียนข้อมูลจาก buffer ลง file จริงๆ

#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];

//———————  Write file ——————-
// Create new file
[[NSFileManagerdefaultManager] createFileAtPath:@”sample.txt”
contents:nilattributes:nil];
// Create file handle
NSFileHandle *fWriteHandle;
fWriteHandle = [NSFileHandlefileHandleForUpdatingAtPath:@"sample.txt"];
if (fWriteHandle == nil)
printf(“File Error”);

char buffer[256] = “Hello “;
NSString *nsBuffer = @”world”;

// Write data
NSData *tempData1 = [NSDatadataWithBytes:buffer
                                  length:strlen(buffer)];
NSData *tempData2 = [NSDatadataWithBytes:[nsBuffer UTF8String]
                                  length:[nsBuffer length]];
[fWriteHandle writeData:tempData1];
[fWriteHandle writeData:tempData2];
[fWriteHandle closeFile];

// ——————– Read file ———————-
NSFileHandle *fReadHandle;
fReadHandle = [NSFileHandlefileHandleForReadingAtPath:@"sample.txt"];
if (fReadHandle == nil)
printf(“File Error”);

NSData *tempData3;
char readBuffer[256] = “”;
// read data to end of file
tempData3 = [fReadHandle readDataToEndOfFile];
// get data to buffer
[tempData3 getBytes:readBuffer];
printf(“\nData in file: \n%s”,readBuffer);
[fReadHandle closeFile];
[pool release];
}

จากตัวอย่างข้างบน แบ่งออกเป็น 2 ส่วนคือ

  • Write Data

สำหรับการเขียนข้อมูลนั้น เมื่อทำการ สร้าง NSFileManager ขึ้นมาแล้ว สิ่งที่เราต้องทำต่อมาก็คือการสร้าง NSData เพื่อที่จะเก็บข้อมูลที่ต้องการเขียนไปยังไฟล์

NSData *tempData1 = [NSDatadataWithBytes:buffer
                                  length:strlen(buffer)];

เราก็ทำการส่ง buffer ไปให้ยัง tempData1 และบอกขนาด buffer ให้เรียบร้อย
หลังจากนั้นก็ให้ NSFileManager ที่เราประกาศไว้เป็นคนเขียน

[fWriteHandle writeData:tempData1];

เพียงเท่านี้เราก็สามารถเขียนข้อมูลลงไฟล์ได้แล้ว

  • Read Data

สำหรับการอ่านข้อมูลนั้นก็ทำงานคล้ายๆกับการเขียนคือ หลังจากประกาศ NSFileManager เสร็จก็ให้ประกาศ NSData ทำการอ่านข้อมูลจาก File มาเก็บไว้ จากตัวอย่าง เราทำการอ่านข้อมูลไปจนสิ้นสุดไฟล์เลย

tempData3 = [fReadHandle readDataToEndOfFile];

แล้วหลังจากนั้น เราก็สร้าง buffer ขึ้นมาเพื่อที่จะนำข้อมูลออกมาจาก NSData อีกที

[tempData3 getBytes:readBuffer];

ก็เป็นตัวอย่างการเขียนและการอ่านไฟล์ แบบง่ายๆ ลองเอาไปหัดใช้กันดู ก็เหมือนเดิม มี source มาให้ด้วยก็โหลดไปลองเล่นกันดู

Download