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

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

Objective-C : Collection (ตอนที่2)

    Dictionary

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

     

    การเก็บข้อมูลโดยการอ้างคีย์นี้จะต้องใช้คีย์ที่ไม่ซ้ำกันแต่อนุญาติให้ คีย์เป็นอ๊อบเจ็คใดๆก็ได้ และใน Foundation Framework ก็แบ่งคลาส dictionary นี้ออกเป็น 2 แบบเช่นเดียวกันกับอาร์เรย์นั่นก็คือ NSMutableDictionary และ NSDictionary จากชื่อคงจะพอเดาได้ว่า NSMutableDictionary คือคลาสที่แก้ไขได้ และคลาส NSDictionary คือแก้ไขเปลี่ยนแปลงไม่ได้

     

    Program 9.3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    #import <Foundation/Foundation.h>
     
    int main(int argc, const char * argv[])
    {
     
        @autoreleasepool {
     
            NSDictionary* urlDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
            @"http://www.google.com",@"google",
            @"http://www.apple.com/th",@"apple",
            @"http://macfeteria.com/tutorial/",@"tutorial",
            @"http://www.google.com",@"google", nil];
     
            NSLog(@"%@" , [urlDictionary objectForKey:@"google"]);
            NSLog(@"%@" , [urlDictionary objectForKey:@"tutorial"]);        
     
        }
        return 0;
    }

    Program 9.3 Output

    http://www.google.com
    http://www.macfeteria.com/tutorial

     

    โปรแกรมประกาศดิกชันนารีชื่อ urlDicationary และได้กำหนดค่าเริ่มต้นให้กับอ๊อบเจ็คด้วยเมธอด initWithObjectsAndKeys: เมธอดนี้ได้รับพารามิเตอร์ที่เป็นอ๊อบเจ็คที่ต้องการจะเก็บ และตามด้วยคีย์ ดังนั้นสตริงตัวแรก @”http://www.google.com” ก็คืออ๊อบเจ็คที่ต้องการจะเก็บและมีคีย์เป็น @”google” นั่นเอง ส่วนค่าที่เหลือก็จะเป็นลักษณะแบบเดียวกันคืออ๊อบเจ็คและคีย์สลับกันไปตาม ลำดับและปิดท้ายด้วย nil ลักษณะเดียวกันกับ NSArray ที่เราเคยได้เขียนไปแล้ว ดิกชันนารีที่เราได้ประกาศไปจึงมีค่าเริ่มต้นตามตารางนี้

     

    table1

     

    หลังจากนั้นเราใช้เมธอด objectForKey: เพื่อใช้สำหรับการขอข้อมูลในดิกชันนารีและแสดงข้อมูลนั้นด้วย NSLog โปรแกรมจึงแสดงผลดังกล่าว ในกรณีที่ไม่สามารถหาข้อมูลที่ต้องการด้วยคีย์ที่กำหนดได้ dictionary จะส่งค่า nil กลับมา

    การจัดเก็บอ๊อบเจ็คของคลาสดิกชันนารีนั้น ค่าของคีย์ไม่จำเป็นต้องเป็นคลาส NSString เสมอไปสามารถใช้คลาสใดๆเป็นคีย์ก็ได้ นอกจากนี้ยังสามารถที่จะจัดเก็บอ๊อบเจ็คที่ต่างกันไว้ได้ในดิกชันนารีเดียว กัน  ลองดูการใช้ดิกชันนารีอีกสักตัวอย่าง

     

    Program 9.4

    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>
     
    int main(int argc, const char * argv[])
    {
     
        @autoreleasepool {
     
            NSNumber* piNumber = [NSNumber numberWithFloat:M_PI];
            NSNumber* primeNumber = [NSNumber numberWithInt:7];
            NSString* primeString = @"7";
     
            NSMutableDictionary* myDict = [NSMutableDictionary dictionary];
     
            [myDict setObject:piNumber forKey:@"pi"];
            [myDict setObject:primeString forKey:primeNumber];
     
            NSLog(@"%@" , [myDict objectForKey:@"pi"]);
            NSLog(@"%@" , [myDict objectForKey:primeNumber]);
     
        }
        return 0;
    }

     

    สร้างอ๊อบเจ๊ค myDict ด้วย class method ของ NSMutableDictionary และใช้เมธอด setObject:forKey ในการจัดเก็บอ๊อบเจ็ค โดยอ๊อบเจ็คแรกเป็นคลาส NSNumber และมีคีย์เป็น NSString ส่วนอ๊อบเจ็คที่สองนั้นตรงกันข้ามกับอ๊อบเจ็คแรกคือมีคีย์เป็น NSNumber และมีอ๊อบเจ็กที่ต้องการจัดเก็บเป็น NSString เมื่อโปรแกรมทำงานจึงแสดงผลดังนี้

     

    Program 9.4 Output

    3.141593
    7

     

    Fast enumeration

    หลังจากที่เริ่มใช้ NSDictionary ไปแล้วจะพบว่าหากมีข้อมูลปริมาณมากๆ แล้วเราต้องการจะดึงข้อมูลที่อยู่ในดิกชันนารี่นั้นมาทั้งหมดจะทำอย่างไร ? แน่นอนว่าถ้าหากรู้คีย์ทั้งหมดของ NSDictionary ก็สามารถขอข้อมูลได้ทั้งหมด แต่ถ้าเราจำคีย์ไม่ได้หรือไม่รู้คีย์ทั้งหมดละ โชคดีที่เราไม่ต้องจำคีย์ทั้งหมด NSDictionary มีเมธอด allKey ที่สามารถขอ key ทั้งหมดที่มีได้ เมื่อเราได้คีย์ท้ังหมดปัญหาก็จบ เช่นตัวอย่างโปแแกรมต่อไปนี้

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    #import <Foundation/Foundation.h>
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            NSDictionary* animal = [NSDictionary dictionaryWithObjectsAndKeys:
                                    @"Chiwawa",@"dog",
                                    @"Sisawat",@"cat",
                                    @"Parrot",@"bird",
                                    @"Siamese fighting fish",@"fish",
                                    nil];
            NSArray* keylist = [animal allKeys];
            for ( int i = 0 ; i < [keylist count] ; i++)
            {
                NSString* key = [keylist objectAtIndex:i];
                NSLog(@"%@",[animal objectForKey:key]);
            }
        }
        return 0;
    }

    Program Output

    Chiwawa
    Sisawat
    Parrot
    Siamese fighting fish

     

    โปรแกรมที่เราได้เขียนไปก็ทำงานได้ถูกต้อง แต่อย่างไรก็ตามวิธีนี้ไม่ใช่วิธีที่มีประสิทธิภาพ เพราะภาษา Objective-C มีวิธีที่ดีกว่านั่นคือ fast enumeration ลักษณะการทำงานของ fast enumeration มีลักษณะคล้ายกับ for loop จากโค้ดของโปรแกรมที่ผ่านมาหากใช้ fast enumeration ก็จะเขียนได้แบบนี้

     

    Program 9.5

    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
    
    #import <Foundation/Foundation.h>
     
    int main(int argc, const char * argv[])
    {
     
        @autoreleasepool {
     
            NSDictionary* animal = [NSDictionary dictionaryWithObjectsAndKeys:
                                    @"Chiwawa",@"dog",
                                    @"Sisawat",@"cat",
                                    @"Parrot",@"bird",
                                    @"Siamese fighting fish",@"fish",
                                    nil];
     
            NSArray* keylist = [animal allKeys];
            for ( int i = 0 ; i < [keylist count] ; i++)
            {
                NSString* key = [keylist objectAtIndex:i];
                NSLog(@"%@",[animal objectForKey:key]);
            }
     
            // Fast enumeration
            NSLog(@"-- Fast enumeration --");
     
            for ( NSString* key in animal)
                NSLog(@"%@",[animal objectForKey:key]);
     
        }
        return 0;
    }

    Program 9.5 Output

    Chiwawa
    Sisawat
    Parrot
    Siamese fighting fish

     

    การใช้ fast enumeration ทำให้โค้ดมีความกระชับมากขึ้นและทำงานได้เร็วขึ้น นอกจากนี้ fast enumeration ยังใช้กับ Collection Class อื่นๆ เช่น NSArray ได้อีกด้วย

     

    Set

    เซ็ทคือคอลเลคชั่นคลาสที่ไม่มีการจัดเรียง ซึ่งจากต่าง NSArray ที่ใช้ลำดับ (index) ในการอ้างอิง ส่วน NSDictionary ก็ใช้ key ในการอ้างอิง คลาส Set ใน Foundation Framework ก็แบ่งออกเป็น 2 แบบเช่นเดียวกันกับอาร์เรย์และดิกชันนารี่ นั่นคือ NSSet และ NSMutableSet

     

    Program 9.6

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    
    #import <Foundation/Foundation.h>
     
    int main(int argc, const char * argv[])
    {
     
        @autoreleasepool {
     
            NSMutableSet *set1 = [NSMutableSet setWithObjects: @"dog", @"cat", @"fish", nil];
            NSSet *set2 = [NSSet setWithObjects:@"cat", @"dog", @"fish", @"rat", nil];
            NSMutableSet *set3 = [NSMutableSet setWithObjects: @"fish", @"cat", @"bird", nil];
     
            // add object
            [set1 addObject:@"bird"];
     
            // fast enumeration
            for ( NSString* item in set1)
                NSLog(@"%@", item);
     
            // Remove object
            [set1 removeObject:@"dog"];
     
            // Test equality
            if([set1 isEqualToSet: set3] )
                NSLog(@"Set1 is equal to Set3");
            else
                NSLog(@"Set1 is equal to Set3");
     
            // Check member
            if([set1 containsObject:@"dog"] )
                NSLog(@"Set1 contains dog");
            else
                NSLog(@"Set1 does not contain dog");
     
            // Union
            [set1 unionSet: set2];
            NSLog(@"Union %@", set1);
     
            // Intersection
            [set1 intersectSet: set3];
            NSLog(@"Intersection %@", set1);
     
            // Get All member
            NSArray* allObject = [set1 allObjects];
            NSLog(@"All Object %@",allObject);
     
        }
        return 0;
    }

    Program 9.6 Output

    cat
    dog
    bird
    fish
    Set1 is equal to Set3
    Set1 does not contain dog
    Union {(
    cat,
    rat,
    dog,
    bird,
    fish
    )}
    Intersection {(
    cat,
    bird,
    fish
    )}
    All Object (
    cat,
    bird,
    fish
    )

     

    จากโค้ดโปรแกรม 9.6 ถ้าสังเกตจะเห็นว่าคลาสเซ็ทนั้นไม่มีเมดธอดที่ใช้ขออ๊อบเจ็คแบบเจาะจงรายตัว เหมือนอย่าง NSArray ที่มี objectAtIndex: หรือ NSDictionary ก็มี objectForKey: เมธอดเดียวที่ NSSet มีให้ในการเข้าถึงอ๊อบเจ็คก็คือ allObjects ซึ่งจะได้ข้อมูลทั้งหมดกลับมาในรูปแบบอาร์เรย์

     

    IndexSet

    คลาส IndexSet แบ่่งออกเป็นสองคลาสเช่นเดียวกับคลาสอื่นๆคือ NSIndexSet และ NSMutableIndexSet คลาสอินเด็กซ์เซ็ทถูกออกแบบให้เก็บข้อมูลประเภทตำแหน่ง (index)

     

    สมมติว่าเราต้องการจะเก็บตำแหน่งของแถวในตารางที่ผู้ใช้งานเลือกไว้ เช่น แถวที่ 1 และแถวที่ 3 , 4 วิธีการที่ง่ายที่สุดก็คือเก็บตำแหน่งที่ถูกเลือกไว้ใน Array แต่วิธีการนี้ไม่มีประสิทธิภาพมากนัก เพราะในบางสถานการณ์ เช่นตารางมี 1000 แถว ผู้ใช้เลือกแถวตั้งแต่ 100 – 250 และตำแหน่ง 312 , 389 , 588 หากเก็บข้อมูลด้วยอาเรย์จะเห็นว่าต้องเก็บค่าตำแหน่งทั้งหมดคือ 153 ค่าด้วยกัน ทางออกที่ดีกว่านั้นคือใช้คลาสที่ออกแบบให้เก็บข้อมูลประเภทตำแหน่ง (index) อย่างเช่น NSIndexSet เพราะคลาสนี้เราสามารถระบุตำแหน่งที่เป็นระยะ และตำแหน่งโดดๆได้ จากเหตุการณ์เดียวกันถ้าเปลี่ยนมาใช้ NSIndexSet เราจะใช้ข้อมูลในการระบุตำแหน่งเพียงแค่ 4 ตัวเท่านั้นคือ (100-250) , 312 , 389 และ 588 เพื่อความเข้าใจลองดูตัวโปรแกรม 9.7

     

    Program 9.7

    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
    
    #import <Foundation/Foundation.h>
     
    int main(int argc, const char * argv[])
    {
     
        @autoreleasepool {
     
            NSValue *pointObj = [NSValue valueWithPoint: CGPointMake(100, 200)];
            NSValue *rectObj = [NSValue valueWithRect:NSMakeRect(10, 20, 10, 10)];
     
            NSLog(@"x position %f",pointObj.pointValue.x);
            NSLog(@"height %f",rectObj.rectValue.size.height);
     
            NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
            [indexSet addIndex: 2];
            [indexSet addIndexesInRange:NSMakeRange(5, 4)];
     
            NSArray* months = [NSArray arrayWithObjects:@"January", @"Feburary" ,
                             @"March",@"April",@"May",@"June",@"July",@"August",
                             @"September",@"October",@"November" , @"December" ,nil];
     
            NSUInteger index = [indexSet firstIndex];
            while(index != NSNotFound)            
            {
                NSLog(@" %@",[months objectAtIndex:index]);            
                index = [indexSet indexGreaterThanIndex: index];
            }
     
            [indexSet release];
        }
        return 0;
    }

     

    จากโค้ดของโปรแกรม 9.7 ได้ประกาศอาเรย์ที่เป็นรายชื่อของเดือนทั้ง 12 เดือน จากนั้นเราประกาศ indexSet ที่เก็บค่า index คือตำแหน่งที่ 2 และระยะตั้งแต่ตำแหน่งที่ 5 จนถึง 4 ตำแหน่งถัดไป ( 5 ถึง 9 )  หลังจากนั้นก็เขียนลูปเพื่อให้แสดงค่าของเดือนที่เราได้เลือกไว้ผลลัพธ์จึง ได้ดังนี้

     

    Program 9.7 Output

    March
    June
    July
    August
    September

     

    NSValue

    ในบางครั้งเราต้องจะเก็บข้อมูลที่เป็นข้อมูลโครงสร้างพื้นฐาน เช่นในการพัฒนาโปรแแกรมด้วย iOS อาจจะจำเป็นต้องเก็บตำแหน่งพิกัดของหน้าจอ x , y หรือต้องการจะเก็บค่าของตำแหน่งปุ่มบนหน้าจอพร้อมขนาดความกว้างยาว x , y , width , height เป็นต้น โครงสร้างข้อมูลเหล่านี้มีอยู่แล้วใน Foudation Framework ซึ่งก็คือ CGPoint , CGRect แต่อย่างไรก็ตามโครงสร้างข้อมูลเหล่านี้ก็ไม่ใช่อ๊อบเจ็ค เพราะเป็นเพียง data structure ของภาษา C เท่านั้น เราจึงไม่อาจจะเก็บค่าเหล่านี้ในคลาสที่เป็น collection เช่น NSArray ได้ การแก้ปัญหาก็คือสร้างคลาสที่ใช้เก็บข้อมูลเหล่านี้ แต่เราไม่ต้องเปลืองแรงไปเรียนคลาสเหล่านี้ เพราะคลาส NSValue ได้ออกแบบให้กับปัญหาเหล่านี้ คลาส NSValue เป็น wrapper class ที่ช่วยในการเก็บ ข้อมูลของ data structure ต่างๆเหล่านี้

     

            NSValue *pointObj = [NSValue valueWithPoint: CGPointMake(100, 200)];
            NSValue *rectObj = [NSValue valueWithRect:NSMakeRect(10, 20, 10, 10)];
     
            NSLog(@"x position %f",pointObj.pointValue.x);
            NSLog(@"height %f",rectObj.rectValue.size.height);

     

    บทนี้เราได้เรียนรู้ collection class ต่างๆของ Foundation Framework กันไปพอสมควร การเลือกคลาสให้เหมาะสมกับการใช้งานก็เป็นสิ่งสำคัญเพราะช่วยให้โปรแกรมของ เรามีประสิทธิภาพดี และการเขียนโค้ดง่ายขึ้น

     

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

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

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