close

本章學習目標:   

1. 了解字串的使用方式。

2. 了解容器類別的使用方式。

 

在前面許多關於Objective-C的基礎觀念介紹之後,在這一章我們將會介紹一些程式中常用的的類別:字串和容器類別,這些類別大多是以往資料結構或是其他計算機課程中在介紹的觀念,不過iOS已經幫我們處理了大部分複雜的功能,因此不過大費周章地全部重頭打造,了解這一章所介紹的類別,對快速開發應用程式有相當大的幫助。

 


 

X.1 字串

Cocoa Touch 提供了字串物件來幫助我們處理字串的工作,Cocoa Touch的字串在內部是使用unicode 字元來儲存資料,不過它也提供了許多方法來和其他的編碼進行轉換,Cocoa的字串分為兩大類:

 

不可改變的字串

NSString

可改變的字串

NSMutableString

 

為了容易分別,在後面的文章中若沒有特別指名的字串,指的就是Cocoa Touch的NSString或是NSMutableString,若是特別提到C字串,指的就是C語言中用來表示字串的 char * 型別。

在Cocoa Touch中,許多類別都有可修改和不可修改兩個版本,這兩者在命名上的差別是可修改的版本會有關鍵字Mutable在類別的名字中,就如同字串的兩個版本NSString和NSMutableString一樣。

字串物件使用unicode字元的陣列來儲存資料,我們可以使用length來得到目前字串內有多少個字元,也可以使用characterAtIndex來得到某個指定位址的字元。

X.1.1 建立和轉換字串物件

NSString 和 NSMutableString提供了許多方法來讓我們產生字串物件,這些建立方法大多是提供讓我們用不同的編碼來產生字串,不過在內部處理上,字串永遠是使用unicode來處理資料,字串提供許多方法在不同編碼之間相互轉換,我們可以使用availableStringEncoding來得到目前允許的編碼方式。

 

X.1.1.1 建立字串

最簡單產生字串物件的方式是使用Objective-C 的字串格式

@”…”,例如:

NSString * temp = @"/temp/scratch";

這種類型的字串擁有和平常字串物件一樣的retain、release之類的方法,不過和其他字串比較不同的地方是這種字串的使用的記憶體要直到程式結束時才會真的被釋放,因為「@"/temp/scratch"」字串在系統裏的角色等同於常數,會為它配置特別的記憶體,除此之外它和其他字串比較的方式也和一般字串相同,請參考下面例子: 

BOOL same = [@"comparison" isEqualToString:myString]; 

X.1.1.2 由資料或是C字串來建立NSString

我們使用如「initWithCString:encoding:」由C字串來產生字串物件,同樣地我們可以使用類似的方法「initWithData:encoding:」來將NSData物件轉換成NSString字串(NSData是用來儲存2進位資料的類別)。

 

char *utf8String = /* 假設這是某個UTF-8字串*/ ;

NSString *stringFromUTFString = [[NSString alloc] initWithUTF8String:utf8String];

 

char *macOSRomanEncodedString = /* 假設這是某個C字串*/ ;

NSString *stringFromMORString =

            [[NSString alloc] initWithCString:macOSRomanEncodedString

                              encoding:NSMacOSRomanStringEncoding];

 

NSData *shiftJISData =  /* 假設這是某個字串資料*/ ;

NSString *stringFromShiftJISData =

            [[NSString alloc] initWithData:shiftJISData

                              encoding:NSShiftJISStringEncoding];

下面的範例示範了如何將UTF-8字串轉成ASC II 資料再轉換成NSString 物件:

unichar ellipsis = 0x2026;

NSString *theString = [NSString stringWithFormat:@"To be continued%C", ellipsis];

 

NSData *asciiData = [theString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

 

NSString *asciiString = [[NSString alloc] initWithData:asciiData encoding:NSASCIIStringEncoding];

 

NSLog(@"原始字串: %@ (長度%d)", theString, [theString length]);

NSLog(@"轉換字串: %@ (長度 %d)", asciiString, [asciiString length]);

 

// 輸出結果:

// 原始字串: To be continued… (長度16)

// 轉換字串: To be continued... (長度 18)

X.1.1.3 連接和擷取字串

我們可以用許多方法來將兩個字串連結在一起,一個簡單的方法是使用「stringByAppendingString:」一個字串直接連接在另一個字串:

 

NSString *beginning = @"beginning";

NSString *alphaAndOmega = [beginning stringByAppendingString:@" and end"];

// alphaAndOmega is @"beginning and end"

若一次要連接許多個字串則可以使用「initWithFormat:」、「stringWithFormat:」或是「stringByAppendingFormat:」我們將在後面的章節介紹這幾個方法的使用方式。

 

我們可以由字串中的某的索引值開始來擷取子字串,如「substringToIndex:」、「substringFromIndex:」和「substringWithRange:」,若要將字串分割則可以使用「componentsSeparatedByString:」,請參考下面的範例:

NSString *source = @"0123456789";

NSString *firstFour = [source substringToIndex:4];

// firstFour 結果是 @"0123"

 

NSString *allButFirstThree = [source substringFromIndex:3];

// allButFirstThree 結果是 @"3456789"

 

NSRange twoToSixRange = NSMakeRange(2, 4);

NSString *twoToSix = [source substringWithRange:twoToSixRange];

// twoToSix 結果是 @"2345"

 

NSArray *split = [source componentsSeparatedByString:@"45"];

// split 最後包含了 { @"0123", @"6789" }

 

X.1.1.4 字串轉換摘要

 

Source 

建立字串 

擷取字串 

In code

@"..."

N/A

UTF8 編碼

stringWithUTF8String:

UTF8String

Unicode 編碼

stringWithCharacters:length:

getCharacters:

getCharacters:range:

任意編碼

initWithData:encoding:

dataUsingEncoding:

現有字串

stringByAppendingString:

stringByAppendingFormat:

N/A

格式化字串

localizedStringWithFormat:

initWithFormat:locale:

使用NSScanner

多國語言

NSLocalizedString  

N/A

X.1.2 格式化字串

這一小節我們將會對格式化字串做一個初步的介紹

X.1.2.1 基本概念

NSString使用的格式化字串和標準的ANSI C的printf()相同,不過加上了「%@」給所有的物件類別,在格式化中「%」表示這個位置將會有一個替代的字串出現,而出現的格式則是依據在「%」之後的符號而定,我們可以使用NSString的「stringWithFormat:」或是「stringByAppendingFormat:」方法來建立格式化字串,此外NSLog()函數也常用格式化字串來顯示資料(NSLog主要是用來記錄程式的執行流程,在除錯時是相當實作的函數),下面列出了常用格式化符號的使用方式:

 

符號 

來源 

型別 

說明 

%@

Objective-C 物件

NSObject

印出 descriptionWithLocale: 或是description 回傳的字串。

%%

 

 

'%' 字元。

%d, %D, %i

有正負號的32 位元整數

int

 

%u, %U

無正負號的 32位元整數

unsigned int

 

%hi

有正負號的16 位元整數

short

 

%hu

無正負號的 16位元整數

unsigned short

 

%qi

有正負號的64 位元整數

long long

 

%qu

無正負號的 64位元整數

unsigned long long

 

%x

無正負號的 32位元整數

unsigned int

 16進位的方式顯示,使用0–9 小寫a–f,例如:

 

來源:1234567890

輸出:499602d2

%X

無正負號的 32位元整數

unsigned int

 16進位的方式顯示,使用0–9 大寫A–F,例如:

 

來源:1234567890

輸出:499602D2

%qx

無正負號的 64位元整數

unsigned long long

16進位的方式顯示,使用0–9小寫 a–f,例如:

 

來源:1234567890

輸出:499602d2

%qX

無正負號的 64位元整數

unsigned long long

16進位的方式顯示,使用0–9大寫 A–F,例如:

 

來源:1234567890

輸出:499602D2

%o, %O

無正負號的 32位元整數

unsigned int

8進位顯示,例如:

 

來源:1234567890

輸出:11145401322

%f

浮點數

double

 

%e

浮點數

double

以科學符號顯示,使用小寫的e來代表指數,例如:

 

來源:1234567890.12345

輸出:1.234568e+09

%E

浮點數

double

以科學符號顯示,使用大寫的E來代表指數,例如:

 

來源:1234567890.12345

輸出:1.234568E+09

%g

浮點數

double

若指數大於4時以 %e 方式顯示,若是小於則是使用和%f相同的方式來顯示,例如:

 

來源:1234567890.12345

輸出:1.23457e+09

 

來源:123.456789012345

輸出:123.457

%G

浮點數

double

若指數大於4時以 %E 方式顯示,若是小於則是使用和%f相同的方式來顯示,例如:

 

來源:1234567890.12345

輸出:1.23457E+09

 

來源:123.456789012345

輸出:123.457

%s

8位元無正負號字元並以Null-結尾的陣列

char *

 

%S

16位元Unicode字元並以Null-結尾的陣列

unichar *

 

%p

void 指標

void *

16進位的方式顯示使用0–9 和小寫的a–f並在開頭加上0x

%L

 

longdouble

配合 a, A, e, E, f, F, g, G顯示指定長度

%F

浮點數

double

以十進位方式顯示

%z

size_t

size_t

配合 d, i, o, u, x, X 顯示指定長度。

下面的範例提供了一些格式化字串的例子:   

 

NSString *string1 = [NSString stringWithFormat:@"A string:%@, a float: %1.2f", @"string", 31415.9265];

// string1 是 "A string: string, a float: 31415.93"

   

NSNumber *number = [NSNumber numberWithInt:1234];

NSDictionary *dictionary = [NSDictionary dictionaryWithObject:[NSDate date] forKey:@"date"];

NSString *baseString = @"Base string.";

   

NSString *string2 = [baseString stringByAppendingFormat:@" A number: %@, a dictionary: %@", number, dictionary];

 // string2 "Base string. A number: 1234, a dictionary: {date = 2005-10-17 09:02:01 -0700; }"

X.1.3 字串和其它型態的轉換

NSString提供了許了將的轉換方式,只要配合格式化的字串,我們很方便地就能在各種格式間轉換,以下列出了常用字串轉換方式:

方法

型態

範例

doubleValue

double

double    data   = [@"3.1416" doubleValue];

floatValue

float

float     fData  = [@"3.1416" floatValue];

intValue

int

int       nData  = [@"1024" intValue];

integerValue

NSInteger

NSInteger nData2 = [@"2048" integerValue];

longLongValue

long long

long long llData = [@"1234567890" longLongValue];

boolValue

BOOL

BOOL      bData  = [@"1" boolValue];

 

X.1.4 由已知編碼下從檔案或是網路上讀取字串

NSString提供了很直覺的方法讓我們直接從檔案中讀取資料,甚至只要提供網路的URL就能將來自網路上的文字直接滙入NSString中,當資料來源編碼是已知的情況下,我們可以使用「stringWithContentsOfFile:encoding:error:」或是「stringWithContentsOfURL:encoding:error:」之類的方法來將資料滙入,下面是一個讀取以UTF8編碼檔案的例子:

 

    NSString *path = @"test.txt";

    NSError *error;   

    NSString *stringFromFileAtPath = [[NSString alloc]

                                      initWithContentsOfFile:path

                                      encoding:NSUTF8StringEncoding

                                      error:&error];

    if (stringFromFileAtPath == nil)

    {

        NSLog(@"讀取檔案失敗 %@\n%@",path, [error localizedFailureReason]);

    }
    [
stringFromFileAtPath release];

 

下面的例子則是假設已知編碼為Big5的前提下,只要使用NSString就能夠把http://www.google.com.tw/ 文字內容取回的例子:

    UInt32 big5 = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingBig5);

    NSURL * url = [NSURL URLWithString:@"http://www.google.com.tw/"];

    NSError *error;   

    NSString *stringFromURL = [[NSString alloc]

                               initWithContentsOfURL:url

                               encoding:big5

                               error:&error];

    if (stringFromURL == nil)

    {

        NSLog(@"讀取網頁失敗 %@\n%@", url, error);

    } 

 

    [stringFromURL release];

X.1.5 由未知編碼下讀取資料

當我們不知道資料是使用什麼編碼方式時,NSString提供我們一些方法來「猜」資料的編碼方式來讀取字串,不過即然是「猜」的就有可能是猜不到,不過在大部分的情況下結果應該是對的,如果猜不到的話就必須使用更多的方式來檢查編碼,這部分就留給讀者自行研究,我們可以使用以下方法來讀取未知編碼的資料:

 

stringWithContentsOfFile:usedEncoding:error:

類別方法,讀取資料

initWithContentsOfFile:usedEncoding:error:

實體方法,讀取資料

stringWithContentsOfURL: url usedEncoding: error:

類別方法,讀取URL

initWithContentsOfURL:url usedEncoding:error:error:

實體方法,讀取URL

 

X.1.6 將資料寫入檔案或是URLs

NSString 提供兩個方法給我們寫入資料:

writeToFile:atomically:encoding:error:

寫入檔案

writeToURL:atomically:encoding:error:

寫入URL

在寫入時,我們必須指定編碼的方式,此外atomically可以讓我們指定是否要使用暫存檔來儲存檔案,使用暫存檔的好處是可以避免檔案在寫入的過程產生意外的錯誤,因此若沒有特別需求的話,寫入時請一律使用暫存檔來寫入資料,請參考下面的範例:

NSString *path = ...;//指定路徑

NSString *string = ...;//指定要寫入的內容

NSError *error;//錯誤產生時儲存錯誤訊息的地方

BOOL ok = [string writeToFile:path atomically:YES

                  encoding:NSUnicodeStringEncoding error:&error];

if (!ok)

{

    // 發生錯誤,印出錯誤訊息

    NSLog(@"Error writing file at %@\n%@",

              path, [error localizedFailureReason]);

}

//繼續其他的工作,

 

X.1.7 讀取、寫入摘要

下面列出了前面提供各個方法的一個摘要:

來源 

讀取 

寫入 

檔案資料

stringWithContentsOfFile:encoding:error:

stringWithContentsOfFile:usedEncoding:error:

writeToFile:atomically:encoding:error:

URL 資料

stringWithContentsOfURL:encoding:error:

stringWithContentsOfURL:usedEncoding:error:

writeToURL:atomically:encoding:error:

 

X.1.8 搜尋、比較

以下是關於搜尋及比較常用的方法:

搜尋 

比較 

rangeOfString:

compare:

rangeOfString:options:

compare:options:

rangeOfString:options:range:

compare:options:range:

rangeOfString:options:range:locale:

compare:options:range:locale:

rangeOfCharacterFromSet:

 

rangeOfCharacterFromSet:options:

rangeOfCharacterFromSet:options:range:

我們使用rangeOfString:來尋找該字串是否為目前的子字串,只有當了字串完全符合搜尋條件時才會得到正確的回傳值,下面我們提供了一個關於字串搜尋的範例:

 

NSString *searchString = @"age";

NSString *beginsTest = @"Agencies";

NSRange prefixRange = [beginsTest rangeOfString:searchString

    options:(NSAnchoredSearch | NSCaseInsensitiveSearch)]; 

// prefixRange = {0, 3} , 表示beginsTest有我們要的字串,由第0個索引值開始,三個字元.

NSString *endsTest = @"BRICOLAGE";

NSRange suffixRange = [endsTest rangeOfString:searchString

    options:(NSAnchoredSearch | NSCaseInsensitiveSearch | NSBackwardsSearch)];

// suffixRange = {6, 3}, endsTest有我們要的字串,由第6個索引值開始,三個字元.

在預設的情況下,比較是逐字比較,接下來是字串比較的範例:

NSString *string1 = @"string1";

NSString *string2 = @"string2";

NSComparisonResult result;

result = [string1 compare:string2];

// result = -1 (NSOrderedAscending), 表示字串1比字串2

但是若遇到以下情形,似乎就不是我們想要的結果:

NSString *string10 = @"string10";

NSString *string2 = @"string2";

NSComparisonResult result;

 

result = [string10 compare:string2];

// result = -1 (NSOrderedAscending)

  這是因為此時的比較是依字元做單位,因此雖然看起來string10應該要比string2要大,但是因為比較時會先用1和2比較所以會變成string10比string2要小的情形發生,若要符合預期的結果,必須要求將數字字串視為是數字來比較才行,此時結果如下:

 

result = [string10 compare:string2 options:NSNumericSearch];

// result = 1 (NSOrderedDescending)

這樣結果就會如我們所預期的了。

X.1.9 小結

在這一小節中我們介紹了許多字串的應用,在實際上NSString還提供了相當多的方法來簡化字串的使用,例如可以計算出字串最後在畫面上會佔有多大面積之類的方法(這個方法在支援多國語系的程式中很重要,因為可以確保資料不會在畫面上亂跑)、路徑轉換、將字串畫到某個區域等等好用的方法,這些方法在SDK中都有詳盡的介紹,想深入研究的讀者可以自行參考。

X.2 容器類別

容器類別主要的功能就是將其它的物件裝起來,也可以說是一堆物件的集合,在Cocoa Touch常用的容器中,依據它的功用,大致上會分成以下類別:

 

Array

陣列,當資料之間有順序關係時,通常會使用陣列來當做容器。

Dictionary

字典,具有「關鍵字─值(Key-Value)」特性的資料時,通常會使用字典來做為容器。

Set

集合,當資料之間沒有順序的關係,可以使用集合來做為容器。

 

底下是這三種類別的示意圖:

 

 

Cocoa Touch提供的容器類別在使用上有一個限制就是容器中的東西必須是一個Cocoa Touch的物件,也就是只有繼承自NSObject的物件才能放到這些容器中,此外,這些容器類別也可以包含了其它的容器類別,例如陣列中的每一個元素可以是一個字典、字典中的元素也可以是一個陣列、或是陣列元素又是另一個陣列等等,在這一小節中我們將對這些常見的容器類別做一個簡單的介紹:

X.2.1.1 陣列:有次序的資料集合

 

 

關於陣列的效能資訊

l   存取陣列中的某一個元素:常數時間。

l   移除或是增加資料到最後面的節點:常數時間。

l   取代陣列中的某個元素:常數時間。

l   在陣列中插入一個元素:線性時間。

 

Cocoa Touch提供了兩種陣列類別供我們使用:

NSArray

不可修改的陣列。

NSMutableArray

可以修改的陣列。

陣列可以包含任何類型的物件,陣列內部的物件並不需要屬於同一個類別,但是陣列不能儲存int、float之類不是物件的的資料,因此若想要將這些資料存入陣列中必須利用NSString、NSValue等類別將這些資料轉換後再存入陣列中。

X.2.1.2 NSArray

這種陣列在初始化完成後就不再允許新增、刪除裏面的物件,但物件本身的修改則是依據該物件本身的設定而定,NSArray提供了直接產生或是由別的陣列拷貝而來的數種建立方式,如:

 

+ (id)arrayWithObject:(id)anObject

建立一個包含anObject的陣列

+ (id)arrayWithObjects:(const id *)objects count:(NSUInteger)cnt

利用一個指向一群物件的指標來產生陣列。

+ (id)arrayWithObjects:(id)firstObj, ...

依序列出要加入的物件,以nil來表示結束。

+ (id)arrayWithArray:(NSArray *)array

由另一個陣列內容來產生陣列。

- (id)initWithObjects:(const id *)objects count:(NSUInteger)cnt

利用一個指向一群物件的指標來產生陣列。

- (id)initWithObjects:(id)firstObj, ...

依序列出要加入的物件,以nil來表示結束。

- (id)initWithArray:(NSArray *)array

由另一個陣列內容來產生陣列。

- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag

由另一個陣列內容來產生陣列,並且決定是否要使用拷貝的方式將這些物件加入。

陣列類別提供了兩個基本的方法來讓我們存取資料:

count

傳回陣列內物件的個數。

objectAtIndex

傳回陣列內某個索引值的物件,索引值由0開始。

 

X.2.1.3 NSMutableArray

若資料在爾後需要修改則必須使用這個類別,這個類別是NSArray的子類別,因此所有可以對NSArray的操作都可以作用於NSMutableArray上,除此之外NSMutableArray尚提供了幾個常用的方法來讓我們操作陣列的內容:

 

addObject:

加入物件。

insertObject:atIndex:

插入物件至指定的位置。

removeLastObject

移除最後一個物件。

removeObjectAtIndex:

移除指定位置的物件。

replaceObjectAtIndex:withObject:

將指定位置的物件替換成另一個物件。

底下的範例示範了對NSMutableArray的操作:

NSMutableArray *array = [NSMutableArray array];

[array addObject:[NSColor blackColor]]; //[]

[array insertObject:[NSColor redColor] atIndex:0]; //[紅黑]

[array insertObject:[NSColor blueColor] atIndex:1]; //[紅藍黑]

[array addObject:[NSColor whiteColor]];//[紅藍黑白]

[array removeObjectsInRange:(NSMakeRange(1, 2))];[藍黑]

//陣列包含了 redColor whiteColor

 

除了一般的操作之外,我們需要特別注意的動作是移除,當我們對一個被陣列移除的元素進行操作是很危險的事,例如:

 

id anObject = [anArray objectAtIndex:0];

[anArray removeObjectAtIndex:0];

// 如果anArray 是唯一擁有anObject的人, 下一行會crash

[anObject someMessage];

 

若要存取一個可能被移除的元素,我們需要先retain需要用的元素,請參考下面的範例:

 

id anObject = [[anArray objectAtIndex:0] retain];

[anArray removeObjectAtIndex:0];

[anObject someMessage];

//請記得在使用完 anObject 後要呼叫release

 

X.2.2 字典:關鍵字的集合

 

字典負責管理一群關鍵字」,在字典中的關鍵字必須是唯一的,也就是說所有的關鍵字都不得重覆,下面是一個字典的示意圖:

 

 

 

關於字典的效能資訊:

l   存取字典中的某個元素:常數時間。

l   設定和移除元素:常數時間。

 

註:以上的資訊假設「關鍵字」以NSString或是其他可以使用hash函數的類別所組成。

 

和字串類似地,字典也分成兩個不同的版本:

NSDictionary

不可修改的字典。

NSMutableDictionary

可以修改的字典。

 

NSDictionary 是不可修改的字典,當你建立完字典後,你不能新增、刪除或是取代裏面的元素,不過你可以修改關鍵字所對應到的值(關鍵字無法修改),若想要修改關鍵字就必須使用NSMutableDictionary。

常用來建立字典的方法有initWithDictionary和dictionaryWithDictionary兩種,舉個例來說如果我們有個NSDictionary的實體myDictionary,我們可以使用下面方法來建立可修改的字典:

NSMutableDictionary *myMutableDictionary = [NSMutableDictionary dictionaryWithDictionary: myDictionary];

 

和使用陣列相同,當我們對一個被字典移除的元素進行操作是很危險的事,如下:

id anObject = [aDictionary objectForKey:theKey];

[aDictionary removeObjectForKey:theKey];

[anObject someMessage]; // 有可能會crash

 

所以若要安全地使用,要先retain物件:

id anObject = [[aDictionary objectForKey:theKey] retain];  

[aDictionary removeObjectForKey:theKey];

[anObject someMessage];

//請記得在使用完 anObject 後要呼叫release

 

下面的例子是NSMutableDicationary加入物件的範例:

NSString *LAST=@"lastName";

NSString *FIRST=@"firstName";

 

NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:

    @"Jo", FIRST, @"Smith", LAST, nil];

NSString *MIDDLE=@"middleInitial";

 

[dict setObject: @"M" forKey:MIDDLE];

 

除此之外我們也可以直接將其他字典中的資料加入我們的字典中,如下面的例子:

NSString *LAST=@"lastName";

NSString *FIRST=@"firstName";

NSString *SUFFIX=@"suffix";

NSString *TITLE=@"title";

 

NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:

    @"Jo", FIRST, @"Smith", LAST, nil];

 

NSDictionary *newDict=[NSDictionary dictionaryWithObjectsAndKeys:

    @"Jones", LAST, @"Hon.", TITLE, @"J.D.", SUFFIX, nil];

 

[dict addEntriesFromDictionary: newDict];

 

若想要列舉所有字典內的元素,可以使用keyEnumerator方法或是利用allKeys取得字典內所有的關鍵字後再依序查詢所有的值。

 

X.2.3 集合:沒有次序物件的集合

 

集合代表的是一群沒有次序關係的物件,當一群物件沒有次序關係時,我們就可以使用集合而不是陣列來管理這些物件。

 

 

 

 

關於集合的效能資訊:

l   存取集合中的元素:常數時間。

l   設定和移除元素:常數時間。

 

註:以上的效能資訊有賴於是否能找到有效的hash函數來尋找物件,否則可能要使用線性時間才能完成以上操作。

NSSet 是不可修改的集合,當你建立完集合後,你不能新增、刪除或是取代裏面的元素,不過你可以裏面物件所對應到的值,若想要更動集合包含的元素,就必須使用NSSet的子類別:NSMutableSet,常用的建立函數有setWithObjects:、initWithArray等等。

 

NSSet提供了許多方法來操作裏面的元素,底下是幾個常用的方法:

 

allObjects

回傳一個包含集合中所有元素的陣列。

anyObject

回傳集合中的某個物件。

count

回傳集合中元素的個數。

member:

回傳集合中某個元素是否和指定的物件相同。

intersectSet:

檢查兩個集合是否至少有一固元素是相同的。

isEqualToSet:

檢查兩個集合是否完全相同。

isSubsetOfSet:

檢查目前集合是否為另一個集合的子集合。

 

 

除了NSSet提供的方法外,NSMutableSet還提供了許多方法來幫助我們操作集合中的元素:

 

addObject:

加入物件到集合中。

addObjectsFromArray:

將指定陣列中的元素加入集合中。

unionSet:

和指定的集全進行聯集。

intersectSet:

和指定的集合進行交集。

removeAllObjects:

移除集合中所有的物件。

removeObjects:

移除集合中指定的物件。

minusSet:

移除和指定集合中相同的物件。

 

如同前面介紹的,當我們對一個被集合移除的元素進行操作是很危險的事,例如:

 

id anObject = [aSet anyObject];

[aSet removeObject:anObject];

// 如果aSet 是唯一擁有anObject的人, 下一行會crash

[anObject someMessage];

 

若要存取一個可能被移除的元素,我們需要先retain需要用的元素,請參考下面的範例:

 

id anObject = [[aSet anyObject] retain];

[aSet removeObject:anObject];

[anObject someMessage];

//請記得在使用完 anObject 後要呼叫release

 

此外,因為在集合中的元素沒有次序的關係,因此必須利用objectEnumerator方法或是使用Objective-C內建的for-each來列舉所有的元素。

X.3 小結

 

這一章介紹的NSStringNSDictionaryNSSet等等類別雖然看起來並不起眼,功能好像也沒有很強大,但是卻是讓程式流程更流暢不可或缺的元素,因此了解本章介紹的內容對爾後程式的開發會有相當大地助益。

待續

arrow
arrow
    全站熱搜

    穿越時空的旅人 發表在 痞客邦 留言(0) 人氣()