รับทําเว็บไซต์ รับทําseo
 
รับทําเว็บไซต์ รับทําseo
บทความที่น่าสนใจ

บทความ ที่น่าสนใจ

Objective-C : Category ,Protocol , Delegate (ตอนที่3)

    Delegation

     

    การประยุกต์ใช้โปรโตคอลที่พบได้บ่อยมากๆอีกอย่างคือ delegate pattern รูปแบบของ pattern นี้จะพบได้บ่อยมากใน iOS และ Cocoa เช่นเดียวกันกับ data source เพราะแนวความคิดและหลักการทำงานของ delegate ก็เหมือนกับ data source ที่เราได้เขียนกันไปแล้ว แต่สิ่งที่ต่างกันคือ data source จะเน้นไปยังการเป็นผู้ให้ข้อมูล ส่วน delegate จะเน้นไปยังการควบคุม เช่นการควบคุม interface 

     

    คลาส TableView ที่ใช้แสดงตารางได้ส่งเมสเซจ cellForRow: ไปยัง delegate เพื่อถามว่าตารางแถวที่ 4 นี้ cell ที่ใช้ในการแสดงผลมีหน้าเป็นอย่างไร จากนั้น delegate ก็ส่ง cell ที่ต้องใช้ในการแสดงผลสำหรับแถวนั้นกลับมาตามรูป หรือ เมื่อผู้ใช้สัมผัสแถวที่ 2 ของตาราง TableView ก็จะส่งเมสเซจถาม delegate อีกว่าต้องการให้ทำหรือไม่ เมื่อ delegate ได้รับเมสเซจก็ตอบ presentEQ กลับมาเพื่อบอกให้ TableView แสดงหน้าปรับ EQ นั่นเอง เห็นได้ว่าคลาส TableView นั้นยืดหยุ่นมากๆ เพราะการแสดงผลแต่ละแถวก็ขึ้นอยู่กับ delegate คลาส TableView มีหน้าที่แค่เอา cell นั้นมาจัดวางในแถว ถ้าต้องการเปลี่ยนการแสดงผลก็เปลี่ยนแค่ delegate และเมื่อมีเหตุการณ์ต่างๆเกิดขึ้นคลาส TableView ก็จะส่งต่อให้ delegate เป็นคนจัดการ หากจะยกตัวอย่างในชีวิตประจำวันให้เห็นภาพ ก็เป็นต้นว่า สมมติผู้รับเหมาจ้างช่างมา 3 คน โดยคนแรกเป็นคนก่อกำแพง ส่วนอีกสองคน คือช่างทาสีและช่างวอลเปเปอร์ จะเห็นว่าช่างปูนทำหน้าที่ก่อกำแพงอย่างเดียวโดยไม่ต้องสนใจว่ากำแพงออกมา หน้าตาอย่างไร เมื่อกำแพงเสร็จหากอยากได้สีฟ้า ก็ให้ช่างทาสีเป็นคนจัดการต่อ แต่ถ้าเกิดเปลี่ยนใจอยากติดวอลเปเปอร์ก็ให้ช่างอีกคนทำให้ ช่างทาสีและติดวอลเปเปอร์ก็เหมือนผู้ช่วยหรือ delegate นั่นเอง

     

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

     

    Program 10.4

    NetworkDelegate.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    #import <Foundation/Foundation.h>
     
    @protocol NetworkDelegate <NSObject>
     
    -(void) connectSuccess:(int)errorCode;
    -(void) receiveData:(NSString*)data;
    -(void) connectFail:(int)errorCode;
     
    @optional
    -(void) authentication;
     
    @end

     

    ในส่วนของโปรโตคอล NetworkDelegate นั้นประกาศเมธอดด้วยกัน 4 เมธอด โดยเมธอดแรก connectSuccess: ใช้สำหรับบอกสถานะการเชื่อมต่อว่าเชื่อมต่อสำเร็จ และมีเมธอด connectFail: สำหรับกรณีเชื่อมต่อผิดพลาด ส่วน receiveData: จะใช้สำหรับจัดการข้อมูลที่ได้จากอินเทอร์เน็ต และสุดท้ายคือ authentication เป็น optional method

     

    NetworkController.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    #import <Foundation/Foundation.h>
    #import "NetworkDelegate.h"
     
    @interface NetworkController : NSObject
    {
        id <NetworkDelegate> _delegate;
    }
     
    @property (retain) id <NetworkDelegate> delegate;
     
    -(void) startConnect;
     
    @end

     

    คลาส NetworkController ประกาศเมธอด startConect เพื่อจำลองเหตุการณ์เชื่อมต่อกับอินเทอร์เน็ต และมี class variable เป็นแบบ id โดยระบุว่าต้องเข้ากันได้กับโปรโตคอล NetworkDelegate

     

    NetworkController.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
    #import "NetworkController.h"
     
    @implementation NetworkController
    -(void) startConnect
    {
        if( _delegate == nil )
            return;
     
        int rand = arc4random_uniform(100);
        if( rand > 50 )
        {
            if( [_delegate respondsToSelector:@selector(authentication)])
                [_delegate authentication];
     
            if( [_delegate respondsToSelector:@selector(connectSuccess:)])
                [_delegate connectSuccess:200];
     
            if( [_delegate respondsToSelector:@selector(receiveData:)])
            {
                for(int i = 0 ; i <= 5 ; i++)
                {
                    sleep(1);
                    NSString* data = [NSString stringWithFormat:@"%d",i];
                    [_delegate receiveData:data];
                }
            }
     
        }
        else
            if( [_delegate respondsToSelector:@selector(connectFail:)])
                [_delegate connectFail:404];
    }
     
    @end

     

    เพื่อความสมจริงในการจำลอง โค้ดส่วน startConnect ใช้ฟังก์ชั่น arc4random_uniform เพื่อสุ่มค่าตั้งแต่ 0 – 100 หากค่าที่ได้เกิน 50 ก็จะถือว่าเชื่อมต่อสำเร็จ เมื่อเชื่อมต่อสำเร็จแล้วในโค้ดบรรทัดที่ 12 จะส่งเมสเซจถาม delgate ว่าได้เขียนเมธอด authentication รองรับไว้หรือไม่ ถ้าหากมีก็จะเรียกเมธอดใหทำงาน แต่ในตัวอย่างโปรแกรมของเราไม่ได้เขียนเมธอดนี้ไว้

     

             if( [_delegate respondsToSelector:@selector(authentication)])
                [_delegate authentication];

     

    เมื่อตรวจสอบเรียบร้อยแล้ว ก็จะส่งสถานะการเชื่อมต่อด้วยเมธอด connectSuccess: พร้อมกับรหัสการเชื่อมต่อ 200 ลำดับต่อมาในบรรทัดที่ 18 เป็นส่วนการทำงานสำคัญ โค้ดส่วน for loop จะหยุดทำงานทุก 1 วินาทีเพื่อจำลองเหตุการณ์ว่ากำลังโหลดข้อมูลจาก internet เมื่อได้ข้อมูลเรียบร้อยจะส่งเมสเซจ receiveData: ให้กับ delegate พร้อมกับข้อมูลที่ได้มา ส่วนสุดท้ายก็คือส่วนที่ใช้จัดการในกรณีที่เชื่อต่อผิดพลาดโดยจะส่งรหัส 404 กลับไป

     

    ต่อไปเราจะเขียนโค้ด MyDelegate ที่เป็นตัวประมวลผลข้อมูล

     MyDelegate.h

    1
    2
    3
    4
    5
    6
    
    #import <Foundation/Foundation.h>
    #import "NetworkDelegate.h"
     
    @interface MyDelegate : NSObject <NetworkDelegate>
     
    @end

     

    MyDelegate.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    #import "MyDelegate.h"
     
    @implementation MyDelegate
    -(void) connectSuccess:(int)errorCode
    {
        NSLog(@"Connect success with code: %d", errorCode);
    }
    -(void) receiveData:(NSString*)data
    {
        NSLog(@"Receive: %@", data);
    }
    -(void) connectFail:(int)errorCode
    {
        NSLog(@"Connect fail with code: %d", errorCode);
    }
    @end

     

    โค้ดในการประมวลข้อมูลของคลาส MyDelegate แค่แสดงผลทาง console ด้วยคำสั่ง NSLog  และในขั้นตอนสุดท้ายคือเขียนโค้ดของโปรแกรม

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    #import <Foundation/Foundation.h>
     
    #import "NetworkController.h"
    #import "MyDelegate.h"
     
    int main(int argc, const char * argv[])
    {
     
        @autoreleasepool
        {
            NetworkController* netController = [[NetworkController alloc] init];
            MyDelegate* myDelegate = [[MyDelegate alloc] init];
     
            netController.delegate = myDelegate;
            [netController startConnect];
     
            [myDelegate release];
            [netController release];
     
        }
        return 0;
    }

     

    เริ่มโปรแกรม เราได้กำหนดให้ myDelegate เป็น delegate ของ netController จากนั้น netController ก็จะจำลองการเชื่อมต่อกับอินเทอร์เน็ตด้วยคำสั่ง startCoonect ออบเจ็กต์ netController ไม่ได้เป็นคนจัดการกับข้อมูลโดยตรงแต่ ผลของการเชื่อมต่อและข้อมูลต่างๆจะถูกส่งไปยัง myDelgate ให้จัดการแทน  เมื่อโปรแกรมทำงานก็จะได้ผลดังนี้

     

    Program 10.4 Output ( > 50 )
    Connect success with code 200
    Received 0
    Received 1
    Received 2
    Received 3
    Received 4
    Received 5

    Program 10.4 Output ( <= 50 )
    Connect fail with code 404

     

    โปรแกรมที่ได้เขียนไปเป็นเพียงจำลองการเชื่อมต่ออินเทอร์เน็ท ไม่ได้เชื่อมต่อจริงๆแต่ประการใด อย่างไรก็ตามเป้าหมายที่แท้จริงของโปรแกรมคือให้เราได้ศึกษาและทดลองเขียน delegate pattern เพราะเป็นคอนเซ็ปสำคัญมาก ยิ่งถ้าต้องเขียน iOS หรือ Mac Application ด้วยแล้ว data source และ delegate เป็นสิ่งต้องเจออย่างแน่นอน

     

    Objective-C delegate , C# delegate , Java Listener

     

    สำหรับผู้ที่เคยเขียนโปรแกรมด้วย C# อาจจะเกิดความสับสนระหว่าง delegate ในภาษา C# กับ delegate ของภาษา Objective-C ในภาษา C# การทำงานของ delegate จะเหมือนกับ function pointer ในภาษา C
    แต่สำหรับภาษา Objective-C จะต่างออกไป เพราะ delegate นั้นเป็นออบเจ็กต์ที่ทำงานให้กับออบเจ็กต์อื่นๆ เช่นโปรแกรมที่เพิ่งได้เขียนไป คลาส MyDelegate จะเป็นตัวที่ทำหน้าที่ประมวลผลข้อมูลแทนคลาส NetworkController
    และสำหรับผู้เคยเขียน Java มาก่อนอาจจะมองว่า delegate ทำหน้าที่คล้ายกับ java listener แต่ทั้งสองแตกต่างกันเพราะ delegate เป็นเพียงออบเจ็กต์ผู้ช่วยเท่านั้นไม่ได้เป็น sub class เหมือนกับ java listener / observer
    นอกจากนี้ java listener ยังไม่มีการทำงานแบบ @optional

     

     

บทความที่น่าสนใจ

บทความ ล่าสุด

บทความ ความรู้ด้านไอที, คอมพิวเตอร์ Techonlogy, Gadget, ความรู้เกี่ยวกับคอมพิวเตอร์ กับทาง SoftMelt.com