Objective-C怎么使用对象集合学习系列二

Objective-C如何使用对象集合学习系列二

  • 学习摘要:

    ● 将数组的内容保存到文件系统中

  • ●  使用 NSDictionary NSMutableDictionary 创建字典

  • ●  在字典中添加与删除对象

  • ●  通过不同方式遍历字典

  • ●  将字典的内容保存到文件系统中 

3.7 操纵数组内容

问题

你希望数组内容能够更具动态性,这样用户或你就可以在数组中添加、删除和插入对象了。然而,NSArray 是不可变类,因此一旦创建 NSArray 对象,你就无法再对其中内容进行任何修改。

解决方案

如果你认为所用的数组需要是动态的,那么请使用 NSMutableArrayNSMutableArrayNSArray 的子类,这样就可以像 NSArray 那样使用 NSMutableArray 了。但 NSMutableArray提供了额外的一些方法,可以通过这些方法在数组列表中添加、删除和插入对象。

说明

首先实例化 NSMutableArray 类,可以使用任何构造函数进行实例化。要想创建新的空

NSMutableArray 对象,只需要使用 alloc init 即可:

NSMutableArray *listOfLetters = [[NSMutableArray alloc] init];

要想向数组中添加对象,需要向数组发送 addObject:消息并且将想要添加到数组中的对象作为参数传递进去:

    [listOfLetters addObject:@"A"];
    [listOfLetters addObject:@"B"];
    [listOfLetters addObject:@"C"];

在使用 addObject:时,总是会将对象添加到数组列表的末尾。如果想要将对象插入到数组中的其他位置,那么需要使用 insertObject:atIndex:方法:

    [listOfLetters insertObject:@"a"
                        atIndex:0];
  这会将对象插入到数组的首个位置。

如果想要将某个索引位置的对象替换为另一个对象,那么可以使用 replaceObjectAtIndex:withObject:方法。下面的代码展示了如何将字符 C 替换为小写字母 c:

    [listOfLetters replaceObjectAtIndex:2
                             withObject:@"c"];

要想交换数组中两个对象的位置,可以使用 exchangeObjectAtIndex:withObjectAtIndex:方法:

    [listOfLetters exchangeObjectAtIndex:0
                       withObjectAtIndex:2];
  当需要删除数组中的对象时,可以选择几种不同的方法。可以删除特定索引位置的对
象,可以删除数组中的最后一个对象,还可以删除列表中的全部对象。如果拥有某个对象
的引用,那么还可以通过对象引用删除数组中的这个对象。如下代码展示了删除对象的各
种方式:

[listOfLetters removeObject:@"A"];[listOfLetters removeObjectAtIndex:1];[listOfLetters removeLastObject];[listOfLetters removeAllObjects];

参见程序清单 3-11代码

程序清单3-11 main.m
#import <Foundation/Foundation.h>

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

@autoreleasepool {
   NSMutableArray *listOfLetters =
   [listOfLetters addObject:@"A"];
   [listOfLetters addObject:@"B"];
   [listOfLetters addObject:@"C"];
[[NSMutableArray alloc] init];
%@", listOfLetters);
NSLog(@"OBJECTS ADDED TO ARRAY:
[listOfLetters insertObject:@"a"

atIndex:0];
NSLog(@"OBJECT 'a' INSERTED INTO ARRAY: %@", listOfLetters);

           [listOfLetters replaceObjectAtIndex:2
                                    withObject:@"c"];

NSLog(@"OBJECT 'c' REPLACED 'C' IN ARRAY: %@", listOfLetters);[listOfLetters exchangeObjectAtIndex:0

                             withObjectAtIndex:2];

NSLog(@"OBJECT AT INDEX 1 EXCHANGED WITH OBJECT AT INDEX 2 IN ARRAY:%@", listOfLetters);

[listOfLetters removeObject:@"A"];
NSLog(@"OBJECT 'A' REMOVED IN ARRAY: %@", listOfLetters);

[listOfLetters removeObjectAtIndex:1];
NSLog(@"OBJECT AT INDEX 1 REMOVED IN ARRAY: %@", listOfLetters);

[listOfLetters removeLastObject];
NSLog(@"LAST OBJECT REMOVED IN ARRAY: %@", listOfLetters);

[listOfLetters removeAllObjects];
NSLog(@"ALL OBJECTS REMOVED IN ARRAY: %@", listOfLetters);

}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。通过控制台查看在使用每个操作后数组都发生了什么变化:

    OBJECTS ADDED TO ARRAY: (
       A,

B,

C)

    OBJECT 'a' INSERTED INTO ARRAY: (
       a,

A,B,C

    )
    OBJECT 'c' REPLACED 'C' IN ARRAY: (

a,A,B, 

 

c

)
OBJECT AT INDEX 1 EXCHANGED WITH OBJECT AT INDEX 2 IN ARRAY: (

B,A,a,c

    )
    OBJECT 'A' REMOVED IN ARRAY: (

B,a,c

    )
    OBJECT AT INDEX 1 REMOVED IN ARRAY: (

B,

c)

    LAST OBJECT REMOVED IN ARRAY: (
       B
    )
    ALL OBJECTS REMOVED IN ARRAY: (
    )

3.8 将数组保存到文件系统中

问题

  你想将数组中的对象保存到文件系统中以供其他程序使用。

解决方案

如果数组包含了数字或字符串对象的列表,那么可以将所有这些对象保存到文件系统中以供后续使用,使用 writeToFile:atomically:方法可以做到这一点。注意,该方法无法处理自定义对象。自定义对象需要使用 NSCoding 协议并使用归档类(参见第 9 )Core Data(参见第 10 )

说明

  该攻略需要创建如下由字符串与数字组成的数组:

NSArray *listOfObjects = [NSArray arrayWithObjects:@"A", @"B", @"C",[NSNumber numberWithInt:1], [NSNumber numberWithInt:2], [NSNumber numberWithInt:3],nil];

  要想将数组保存到文件系统中,首先需要如下文件引用:
    NSString *filePathName = @"/Users/Shared/array.txt";

说明:

本攻略假设你使用的是 Mac 应用。iOS 文件引用的工作方式与此不同,参见 2.5 节以了解如何获得 iOS 文件引用。

现在可以使用 writeToFile:atomically:方法将数组内容写到 Mac 文件系统中:[listOfObjects writeToFile:filePathName

                     atomically:YES];

参见程序清单 3-12代码

程序清单3-12 main.m
#import <Foundation/Foundation.h>

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

@autoreleasepool {
NSArray *listOfObjects = [NSArray arrayWithObjects:@"A", @"B", @"C",

[NSNumber numberWithInt:1], [NSNumber numberWithInt:2], [NSNumbernumberWithInt:3], nil];

NSString *filePathName = @"/Users/Shared/array.txt";[listOfObjects writeToFile:filePathName

Objective-C怎么使用对象集合学习系列二Objective-C怎么使用对象集合学习系列二

}

return 0;}

使用

atomically:YES];

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。使用 Finder 找到创建的文件,位于/Users/Shared/array.txt。下面列出文本文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"

"http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0">
<array>

           <string>A</string>
           <string>B</string>
           <string>C</string>
           <integer>1</integer>
           <integer>2</integer>
           <integer>3</integer>

</array> 

</plist>

数据以 XML 格式组织为属性列表(一种存储键数据的 Objective-C 格式)

3.9 从文件系统读取数组

问题

  有一些应用可以访问到的文件,其中包含了以数组形式组织的内容,你想在应用中使
用这些内容。

解决方案

如果你有通过数组创建的文件(使用 writeToFile:atomically:方法保存),那么可以使用initWithContentsOfFile:构造函数实例化新的数组,新数组是由文件内容构成的。

说明

本攻略使用 3.8 节中的文件(已将数组的内容保存到文件系统中)。因此,这里会使用相同的文件路径名:

    NSString *filePathName = @"/Users/Shared/array.txt";

接下来就可以使用 initWithContentsOfFile:构造函数创建由文件内容构成的新数组:NSArray *listOfObjects = [[NSArray alloc] initWithContentsOfFile:filePathName];参见程序清单 3-13

代码

程序清单3-13 main.m
#import <Foundation/Foundation.h>

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

@autoreleasepool {
NSString *filePathName = @"/Users/Shared/array.txt";NSArray *listOfObjects = [[NSArray alloc]

               initWithContentsOfFile:filePathName];
           NSLog(@"%@", listOfObjects);

注意:

本攻略假设你使用的是 Mac 应用。iOS 文件引用的工作方式与此不同,参见 2.5 节以了解如何获得 iOS 文件引用。 


}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。通过日志可以查看数组内容:(

A,B,C,1,2,3

)

3.10 创建字典

问题

  应用需要对列表中的对象进行分组,你想要通过键来引用对象。

解决方案

可以通过两个 Objective-C Foundation 类——NSDictionary NSMutableDictionary 来创建带有键的对象列表。如果不需要修改列表,就使用 NSDictionary;如果在后面要向字典中添加或删除对象,就使用 NSMutableDictionary

说明

Objective-C 中,字典的创建与其他对象一样:可以使用 alloc init 构造函数,或者使用 dictionaryWithObjects:forKeys:等便捷函数创建字典。如果使用 NSDictionary 创建字典,那么字典一旦创建完毕后,就无法再进行修改。使用 NSMutableDictionary 创建的字典可以在后面进行修改。

在下面的示例中,创建的字典包含了不同语言版本的 Hello World。该短语的每个版本都会被录入到相应的语言中:

NSArray *listOfObjects = [NSArray arrayWithObjects:@"Hello World",@"Bonjour tout le monde", @"Hola Mundo", nil];

NSArray *listOfKeys = [NSArray arrayWithObjects:@"english", @"french",@"spanish", nil];

NSDictionary *dictionary2 = [NSDictionarydictionaryWithObjects:listOfObjects forKeys:listOfKeys];


NSDictionary 构造函数 arrayWithObjects:forKeys:需要两个数组作为参数。第一个数组必须包含待存储的对象,第二个数组必须包含与这些对象关联的键。

如果使用 NSMutableDictionary,那么可以通过相同的构造函数创建字典(NSMutable-Dictionary NSDictionary 的子类)。如果后面还要向字典中添加对象,那么还可以通过alloc init 来创建 NSMutableDictionary 对象。表 3-3 完整列出了 NSDictionary NSMutable-Dictionary 类的构造函数,程序清单 3-14 列出了相关代码。 

Objective-C怎么使用对象集合学习系列二

代码

程序清单3-14 main.m
#import <Foundation/Foundation.h>

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

Objective-C怎么使用对象集合学习系列二Objective-C怎么使用对象集合学习系列二

@autoreleasepool {
NSDictionary *dictionary1 = [[NSDictionary alloc] init];
NSArray *listOfObjects = [NSArray arrayWithObjects:@"Hello World",

@"Bonjour tout le monde", @"Hola Mundo", nil];
NSArray *listOfKeys = [NSArray arrayWithObjects:@"english",

     @"french", @"spanish", nil];
   NSDictionary *dictionary2 = [NSDictionary

dictionaryWithObjects:listOfObject forKeys:listOfKeys];NSLog(@"dictionary2 = %@", dictionary2); 

}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。可以设置断点并使用 Xcode调试器查看这些字典的内容。3.11 节将会介绍如何引用每个字典元素,这样就可以将它们的内容打印到日志中或是在程序的其他地方使用它们了。你会看到字典的全部内容被打印到日志中:

    dictionary2 = {
       english = "Hello World";
       french = "Bonjour tout le monde";
       spanish = "Hola Mundo";

}

3.11 引用数组中的对象

问题

  你想要获得指向字典中对象的引用以便访问它们的属性或是向对象发送消息。

解决方案

使用 objectForKey:方法可以获得与你提供的键相对应的对象引用。说明

NSDictionary 根据你提供的键来组织对象。这样一来,查找对象就变得非常简单和快速。只需要使用 objectForKey:并提供与想要查找的对象相对应的键,就可以获得对象引用:

NSString *helloWorld = [dictionary objectForKey:@"english"];

参见程序清单 3-15代码

程序清单3-15 main.m
#import <Foundation/Foundation.h>

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

@autoreleasepool {
NSArray *listOfObjects = [NSArray arrayWithObjects:@"Hello World", 

@"Bonjour tout le monde", @"Hola Mundo", nil];
NSArray *listOfKeys = [NSArray arrayWithObjects:@"english",

@"french", @"spanish", nil];NSDictionary *dictionary = [NSDictionary

dictionaryWithObjects:listOfObjects forKeys:listOfKeys];NSString *helloWorld = [dictionary objectForKey:@"english"];NSLog(@"%@", helloWorld);

Objective-C怎么使用对象集合学习系列二Objective-C怎么使用对象集合学习系列二

84

}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。打印出的 hello world 消息是与English 键对应的对象:

Hello World

要想查看法语版本的 hello world 消息,请将下述代码添加到应用中:helloWorld = [dictionary objectForKey:@"french"];

    NSLog(@"%@", helloWorld);

再次运行应用,检查最后一条控制台消息,你会看到法语版本的 hello world 消息。可以针对西班牙语进行同样操作。

3.12 获取字典中元素的数量

问题

  应用使用了字典中的内容,你需要知道字典中有多少元素以便能恰当地显示出内容。

解决方案

NSDictionary 对象提供了 count 属性,可以通过该属性获得字典中元素的数量。说明

要想使用 count 属性,可以对字典对象使用点符号(dictionary.count)或是发送 count 消息([dictionary count]),从而获得字典中元素的数量。参见程序清单 3-16

代码
程序清单3-16 main.m

    #import <Foundation/Foundation.h>

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

@autoreleasepool {
NSArray *listOfObjects = [NSArray arrayWithObjects:@"Hello World",

@"Bonjour tout le monde", @"Hola Mundo", nil];
NSArray *listOfKeys = [NSArray arrayWithObjects:@"english",

@"french", @"spanish", nil];NSDictionary *dictionary = [NSDictionary

dictionaryWithObjects:listOfObjects forKeys:listOfKeys];NSUInteger count = dictionary.count;
NSLog(@"The dictionary contains %lu items", count);

}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。日志消息会显示出元素的数量:The dictionary contains 3 items

3.13 遍历字典

问题

  你有了对象字典,想要对字典中的每个对象发送相同的消息或是访问同样的属性。

解决方案

使用 NSDictionary 函数 allValues 将字典转换为数组,接下来就可以使用 for-each 循环了,此外还可以使用 enumerateKeysAndObjectsUsingBlock:方法来处理字典中的每个对象。

说明

NSDictionary 对象提供了内置方式来遍历对象列表。然而,如果想要使用 3.4 节中介绍的方式,那么可以临时将字典的键与对象内容转换为数组。例如,要想使用 for-each 循环遍历字典中的对象,可以通过如下代码实现:

    for (NSString *s in [dictionary allValues]) {
       NSLog(@"value: %@", s);

}

NSDictionary 函数 allValues 会返回以数组而非字典形式组织的对象。函数 allKeys 会将键值作为数组返回: 

 for (NSString *s in [dictionary allKeys]) {
         NSLog(@"key: %@", s);

}

还可以使用块,通过 enumerateKeysAndObjectsUsingBlock:方法针对字典中的每个对象执行代码。可以用来定义代码块,然后应用到字典中的每个对象,同时又不必创建 for-each循环或是获得数组版本的字典引用:

[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {NSLog(@"key = %@ and obj = %@", key, obj);

}];

参见程序清单 3-17代码

程序清单3-17 main.m
#import <Foundation/Foundation.h>

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

@autoreleasepool {
NSArray *listOfObjects = [NSArray arrayWithObjects:@"Hello World",

@"Bonjour tout le monde", @"Hola Mundo", nil];
NSArray *listOfKeys = [NSArray arrayWithObjects:@"english",

@"french", @"spanish", nil];NSDictionary *dictionary = [NSDictionary

dictionaryWithObjects:listOfObjects forKeys:listOfKeys];for (NSString *s in [dictionary allValues]) {

                NSLog(@"value: %@", s);
             }

for (NSString *s in [dictionary allKeys]) {NSLog(@"key: %@", s);

}

[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj,BOOL *stop) {

NSLog(@"key = %@ and obj = %@", key, obj);}];

}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。日志消息会显示出使用各种方 

式遍历字典后的结果:

value: Hello World
value: Bonjour tout le monde
value: Hola Mundo
key: english
key: french
key: spanish
key = english and obj = Hello World
key = french and obj = Bonjour tout le mondekey = spanish and obj = Hola Mundo

3.14 操纵字典内容问题

你希望字典内容能够更具动态性,这样用户或你就可以在字典中添加、删除和插入对象了。然而,NSDictionary 是不可变类,因此一旦创建 NSDictionary 对象,你就无法再修改其中的内容。

解决方案

如果知道字典会动态变化,那么请使用 NSMutableDictionaryNSMutableDictionary NSDictionary 的子类,这意味着可以像使用 NSDictionary 那样使用 NSMutableDictionary。但 NSMutableDictionary 提供了额外的一些方法,可以在字典中添加、删除和插入对象。

说明

首先需要实例化 NSMutableDictionary 类,可以通过任何构造函数做到这一点。要想创建新的、空的 NSMutableDictionary 对象,只需要使用 alloc init 即可:

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];

要想向字典中添加对象,需要向字典发送 setObject:forKey:消息,同时带上要添加的对象以及与对象关联的键:

    [dictionary setObject:@"Hello World"
                  forKey:@"english"];

[dictionary setObject:@"Bonjour tout le monde"forKey:@"french"];

    [dictionary setObject:@"Hola Mundo
                  forKey:@"spanish"];

在使用 setObject:forKey:时,你向字典中添加的对象一定是由你提供的键索引的。要想从字典中删除对象,就必须拥有与对象匹配的键。如果拥有键,那么可以通过

removeObjectForKey:方法删除对象:

[dictionary removeObjectForKey:@"french"];

最后,可以通过 removeAllObjects:方法一次性删除字典中的全部对象。参见程序清单3-18

代码
程序清单3-18 main.m

    #import <Foundation/Foundation.h>

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

@autoreleasepool {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];[dictionary setObject:@"Hello World"

                         forKey:@"english"];
           [dictionary setObject:@"Bonjour tout le monde"
                         forKey:@"french"];
           [dictionary setObject:@"Hola Mundo"

forKey:@"spanish"];
NSLog(@"OBJECTS ADDED TO DICTIONARY: %@", dictionary);

[dictionary removeObjectForKey:@"french"];
NSLog(@"OBJECT REMOVED FROM DICTIONARY: %@", dictionary);[dictionary removeAllObjects];
NSLog(@"ALL OBJECTS REMOVED FROM DICTIONARY: %@", dictionary);

}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。通过日志控制台,可以查看在应用每个操作后字典都发生了哪些变化:

    OBJECTS ADDED TO DICTIONARY: {
       english = "Hello World";
       french = "Bonjour tout le monde";
       spanish = "Hola Mundo";
    }
    OBJECT REMOVED FROM DICTIONARY: {
       english = "Hello World";
       spanish = "Hola Mundo";
    }
    ALL OBJECTS REMOVED FROM DICTIONARY: {
    }

3.15 将字典保存到文件系统中

问题

  你想将字典中的对象保存到文件系统中以供日后或是其他程序使用。

解决方案

如果字典中包含数字或字符串对象的列表,那么可以将所有这些对象保存到文件系统中以供后续使用,使用 writeToFile:atomically:方法可以做到这一点。注意,该方法无法处理自定义对象。

说明

  该攻略需要创建如下字典,其中的内容是与键匹配的短语:

NSArray *listOfObjects = [NSArray arrayWithObjects:@"Hello World",@"Bonjour tout le monde", @"Hola Mundo", nil];

NSArray *listOfKeys = [NSArray arrayWithObjects:@"english", @"french",@"spanish", nil];

NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:listOfObjectsforKeys:listOfKeys];

  要想将字典保存到文件系统中,首先需要获得如下文件引用:

NSString *filePathName = @"/Users/Shared/dictionary.txt";

现在可以使用 writeToFile:atomically:方法将字典内容写到 Mac 文件系统中:[dictionary writeToFile:filePathName

                 atomically:YES];

参见程序清单 3-19代码

程序清单3-19 main.m
#import <Foundation/Foundation.h>

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

@autoreleasepool {
NSArray *listOfObjects = [NSArray arrayWithObjects:@"Hello World",

@"Bonjour tout le monde", @"Hola Mundo", nil];
NSArray *listOfKeys = [NSArray arrayWithObjects:@"english",

@"french", @"spanish", nil];NSDictionary *dictionary = [NSDictionary

dictionaryWithObjects:listOfObjects forKeys:listOfKeys];NSString *filePathName = @"/Users/Shared/dictionary.txt";[dictionary writeToFile:filePathName

Objective-C怎么使用对象集合学习系列二Objective-C怎么使用对象集合学习系列二Objective-C怎么使用对象集合学习系列二

}

return 0;}

使用

atomically:YES];

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。使用 Finder 找到创建的文件,位于/Users/Shared/dictionary.txt。下面列出文本文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"

"http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0">
<dict>

             <key>english</key>
             <string>Hello World</string>
             <key>french</key>
             <string>Bonjour tout le monde</string>
             <key>spanish</key>
             <string>Hola Mundo</string>
      </dict>
      </plist>

数据以 XML 格式组织为属性列表(一种存储键数据的 Objective-C 格式)

3.16 从文件系统读取字典

问题

   有一些应用可以访问到的文件,其中包含了以字典形式组织的内容,你想在应用中使
 用这些内容。

解决方案

如果有了通过字典创建的文件(使用 writeToFile:atomically:方法保存),那么可以使用

initWithContentsOfFile:构造函数实例化新的字典,新字典是由文件内容构成的。说明

本攻略使用 3.15 节中的文件(已将字典的内容保存到文件系统中)。因此,这里会使用相同的文件路径名:

NSString *filePathName = @"/Users/Shared/dictionary.txt";

接下来就可以使用 initWithContentsOfFile:构造函数创建由文件内容构成的新字典:NSDictionary *dictionary = [[NSDictionary alloc]

        initWithContentsOfFile:filePathName];

参见程序清单 3-20代码

程序清单3-20 main.m
#import <Foundation/Foundation.h>

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

@autoreleasepool {
NSString *filePathName = @"/Users/Shared/dictionary.txt";NSDictionary *dictionary = [[NSDictionary alloc]

initWithContentsOfFile:filePathName];NSLog(@"dictionary: %@", dictionary);

}

return 0;}

使用

要想使用上述代码,请从 Xcode 构建并运行 Mac 应用。可通过日志查看字典的内容:

    dictionary: {
       english = "Hello World";
       french = "Bonjour tout le monde";
       spanish = "Hola Mundo";

}