【IOS 开发学习总结-OC-29】★★objective-c之foundation 框架——(集合类)数组

来源:互联网 发布:edf调度算法举例 编辑:程序博客网 时间:2024/05/21 06:18

数组代表元素有序,可重复的一个集合,集合中每个元素都有其对应的顺序索引。索引值从0开始,索引值为0代表数组的第一个元素。

NSArray的功能和用法

创建NSArray有2种方法:类方法和实例方法。区别是:类方法以 array 开始,实例方法以 init 开头。
常见的创建NSArray的几种方法:
1. array:创建一个不包含任何 元素的空NSArray。
2. arrayWithObject:/initWithObject::创建只包含指定元素的 NSArray。
3. arrayWithObjects:/initWithObjects::创建包含N个元素的 NSArray。
4. arrayWithContentsOfFile:/initWithContentsOfFile::读取文件内容来创建NSArray。

NSArray集合最大的特点是集合元素有索引——它的大部分用法都与集合元素的索引有关。NSArray集合的方法大致可以分为如下几类:
1. 查询集合元素在NSArray的索引
2. 根据索引值取出NSArray集合中的元素
3. 对集合元素整体调用方法
4. 对NSArray集合进行排序
5. 取出 NSArray集合中的部分元素组成新的集合

用法示范代码 :
NSArrayTest.m

#import <Foundation/Foundation.h>int main(int argc , char * argv[]){    @autoreleasepool{        NSArray* array = [NSArray arrayWithObjects:            @"疯狂iOS讲义", @"疯狂Android讲义"             , @"疯狂Ajax讲义", @"疯狂XML讲义"            , @"Struts 2.x权威指南" , nil];        NSLog(@"第一个元素:%@" , [array objectAtIndex:0]);        //这里要说明一下 ,访问某索引处的元素,也可以用普通数组的下标表示法来访问,比如上面可以用下面这句代码替换        //NSLog(@"第一个元素:%@" , array[0]);        NSLog(@"索引为1的元素:%@" , [array objectAtIndex:1]);        NSLog(@"最后一个元素:%@" , [array lastObject]);        // 获取索引从2~5的元素组成的新集合        NSArray* arr1 = [array objectsAtIndexes: [NSIndexSet             indexSetWithIndexesInRange:NSMakeRange(2, 3)]];        NSLog(@"%@" , arr1);        // 获取元素在集合中的位置        NSLog(@"疯狂Android讲义的位置为:%ld" ,             [array indexOfObject:@"疯狂Android讲义"]);        // 获取元素在集合的指定范围中的位置        NSLog(@"在2~5范围疯狂Android讲义的位置为:%ld" ,             [array indexOfObject:@"疯狂Android讲义"            inRange:NSMakeRange(2, 3)]);  // ①        // 向数组的最后追加一个元素。        // 原NSArray本身并没有改变,只是将新返回的NSArray赋给array        array = [array arrayByAddingObject:@"孙悟空"];        // 向array数组的最后追加另一个数组的所有元素。        // 原NSArray本身并没有改变,只是将新返回的NSArray赋给array        array = [array arrayByAddingObjectsFromArray:            [NSArray arrayWithObjects:@"宝玉" , @"黛玉" , nil]];        for (int i = 0 ; i < array.count; i++)        {//          NSLog(@"%@" , [array objectAtIndex:i]);            // 上面代码也可简写为如下代码            NSLog(@"%@" , array[i]);        }        // 获取array数组中索引为5~8处的所有元素        NSArray* arr2 = [array subarrayWithRange: NSMakeRange(5, 3)];        // 将NSArray集合的元素写入文件        [arr2 writeToFile:@"myFile.txt" atomically:YES];    }}

nil表示NSArray元素结束——这个 nil 元素不会存入NSArray集合中。
上面的程序中用到了 NSIndexSet 集合,它与NSSet 集合功能相似,区别只是主要用于保存索引值 ,所以,它的集合元素都是 NSUInteger 对象。

上面的代码在 NSArray 集合后追加元素后,对于原来的NSArray对象都不会产生任何修改(NSArray集合时候hi 不可修改的),程序只是返回一个新的NSArray对象。

NSArray怎么判断集合是否包含指定元素呢?

判断指定元素位于NSArray 集合中的索引,那么NSArray怎么判断集合是否包含指定元素呢?
判断标准只有一个:只有某个集合元素与被查找元素通过 isEqual:方法比较返回 YES,即可认为该NSArray集合包含该元素,并不需要2个元素是同一元素。

参考资料:
关于NSArray的比较机制可以参考:《疯狂 IOS 讲义(上)》的P273-275

对集合元素整体调用方法

如何简单地对NSArray集合所有或部分元素整体调用方法

NSArray允许对集合中所有的元素或 部分元素整体调用方法,如果只是简单地调用集合元素的方法,可以通过 NSArray的如下2种方法:
1. makeObjectsPerformSelector:——依次调用NSArray集合中 每个元素的指定方法,该方法需要传入一个 SEL 参数,用于指定调用哪种方法。
2. makeObjectsPerformSelector:withObject:依次调用NSArray集合中 每个元素的指定方法,该方法第一个 SEL 参数,用于指定调用哪种方法。第二个参数用于调用集合元素得到方法时传入参数。

如何对NSArray集合中的所有元素进行隐式遍历,并使用集合元素来执行某一段代码

可以通过NSArray的如下方法来完成:
1. enumerateObjectsAtIndexes: options: usingBlock:——遍历集合中指定范围内的元素,并依次使用元素来执行指定的代码块。该方法可以传入一个参数,用于控制遍历的选项,如反向遍历。
2. enumerateObjectsUsingBlock:——遍历集合中所有的元素,并依次使用 元素来执行指定的代码块。
3. enumerateObjectsWithOptions:usingBlock:遍历集合中所有的元素,并依次使用 元素来执行指定的代码块。该方法可以传入一个参数,用于控制遍历的选项,如反向遍历。

说明:上面3个方法中,都需要传入一个代码块参数,该代码块必须带3个参数——第一个参数代表正在遍历的集合元素,第二个参数代表正在遍历的集合元素的索引。

示例代码:
FKUser.h

#import <Foundation/Foundation.h>@interface FKUser : NSObject@property (nonatomic , copy) NSString* name;@property (nonatomic , copy) NSString* pass;- (id) initWithName:(NSString*) aName    pass:(NSString*) aPass;- (void) say:(NSString*) content;@end

FKUser.m

#import "FKUser.h"@implementation FKUser@synthesize name;@synthesize pass;- (id) initWithName:(NSString*) aName    pass:(NSString*) aPass{    if(self = [super init])    {        name = aName;        pass = aPass;    }    return self;}- (void) say:(NSString*) content{    NSLog(@"%@说:%@",self.name , content);}// 会重写isEqual:方法,重写该方法的比较标准是,// 如果两个FKUser的name、pass相等,即可认为两个FKUser相等。- (BOOL) isEqual:(id)other{    if(self == other)    {        return YES;    }    if([other class] == FKUser.class)    {        FKUser* target = (FKUser*)other;        return [self.name isEqualToString:target.name]            && [self.pass isEqualToString:target.pass];    }    return NO;}// 重写description方法,可以直接看到FKUser对象的状态- (NSString*) description{    return [NSString stringWithFormat:        @"<FKUser[name=%@, pass=%@]>"        , self.name , self.pass];}@end

FKUserTest.m

#import <Foundation/Foundation.h>#import "FKUser.h"int main(int argc , char * argv[]){    @autoreleasepool{        // 初始化NSArray对象        NSArray* array = [NSArray arrayWithObjects:            [[FKUser alloc] initWithName:@"sun" pass:@"123"],            [[FKUser alloc] initWithName:@"bai" pass:@"345"],            [[FKUser alloc] initWithName:@"zhu" pass:@"654"],            [[FKUser alloc] initWithName:@"tang" pass:@"178"],            [[FKUser alloc] initWithName:@"niu" pass:@"155"],            nil];        // 对集合元素整体调用方法        [array makeObjectsPerformSelector:@selector(say:)            withObject:@"下午好,NSArray真强大!"];        NSString* content = @"疯狂iOS讲义";        // 迭代集合内指定范围内元素,并使用该元素来执行代码块        [array enumerateObjectsAtIndexes:             [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2,2)]            options:NSEnumerationReverse            // 代码块的第一个参数代表正在遍历的集合元素            // 代码块的第二个参数代表正在遍历的集合元素的索引            usingBlock: ^(id obj, NSUInteger idx, BOOL *stop)            {                NSLog(@"正在处理第%ld个元素:%@" , idx , obj);                [obj say:content];            }];    }}#import <Foundation/Foundation.h>#import "FKUser.h"int main(int argc , char * argv[]){    @autoreleasepool{        // 初始化NSArray对象        NSArray* array = [NSArray arrayWithObjects:            [[FKUser alloc] initWithName:@"sun" pass:@"123"],            [[FKUser alloc] initWithName:@"bai" pass:@"345"],            [[FKUser alloc] initWithName:@"zhu" pass:@"654"],            [[FKUser alloc] initWithName:@"tang" pass:@"178"],            [[FKUser alloc] initWithName:@"niu" pass:@"155"],            nil];        // 对集合元素整体调用方法        [array makeObjectsPerformSelector:@selector(say:)            withObject:@"下午好,NSArray真强大!"];        NSString* content = @"疯狂iOS讲义";        // 迭代集合内指定范围内元素,并使用该元素来执行代码块        [array enumerateObjectsAtIndexes:             [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2,2)]            options:NSEnumerationReverse            // 代码块的第一个参数代表正在遍历的集合元素            // 代码块的第二个参数代表正在遍历的集合元素的索引            usingBlock: ^(id obj, NSUInteger idx, BOOL *stop)            {                NSLog(@"正在处理第%ld个元素:%@" , idx , obj);                [obj say:content];            }];    }}

编译运行结果:

2015-10-03 07:58:26.724 923[1066:16059] sun说:下午好,NSArray真强大!2015-10-03 07:58:26.726 923[1066:16059] bai说:下午好,NSArray真强大!2015-10-03 07:58:26.727 923[1066:16059] zhu说:下午好,NSArray真强大!2015-10-03 07:58:26.727 923[1066:16059] tang说:下午好,NSArray真强大!2015-10-03 07:58:26.728 923[1066:16059] niu说:下午好,NSArray真强大!2015-10-03 07:58:26.729 923[1066:16059] 正在处理第3个元素:<FKUser[name=tang, pass=178]>2015-10-03 07:58:26.730 923[1066:16059] tang说:疯狂iOS讲义2015-10-03 07:58:26.730 923[1066:16059] 正在处理第2个元素:<FKUser[name=zhu, pass=654]>2015-10-03 07:58:26.730 923[1066:16059] zhu说:疯狂iOS讲义

对 NSArray 进行排序

NSArray提供的对集合元素进行排序的方法,都以 sort 开头。常用的排序方法如下:
1. sortedArrayUsingSelector:——使用集合元素自身的方法对集合元素进行排序,集合元素的方法必须返回 NSOrderedDescending,NSOrderedAscending,NSOrderedSame 这些枚举值,用于代表集合元素的大小。本方法返回一个排好序的新NSArray对象。
2. sortedArrayUsingFunction:context:该方法使用排序函数对集合元素进行排序,该排序函数必须返回NSOrderedDescending,NSOrderedAscending,NSOrderedSame 这些枚举值,用于代表集合元素的大小。本方法返回一个排好序的新NSArray对象。
3. sortedArrayUsingComparator:该方法使用代码块对集合元素进行排序,该代码块必须返回NSOrderedDescending,NSOrderedAscending,NSOrderedSame 这些枚举值,用于代表集合元素的大小。本方法返回一个排好序的新NSArray对象。

实际上,sortedArrayUsingComparator:sortedArrayUsingFunction:context:的简化版本。
示例代码:

#import <Foundation/Foundation.h>// 定义比较函数,根据两个对象的intValue进行比较NSInteger intSort(id num1, id num2, void *context){    int v1 = [num1 intValue];    int v2 = [num2 intValue];    if (v1 < v2)        return NSOrderedAscending;    else if (v1 > v2)        return NSOrderedDescending;    else        return NSOrderedSame;}int main(int argc , char * argv[]){    @autoreleasepool{        // 初始化一个元素为NSString的NSArray对象        NSArray* array1 = [NSArray arrayWithObjects:            @"Objective-C" , @"C" , @"C++"             , @"Ruby" , @"Perl" , @"Python" , nil];         // 使用集合元素的compare:方法执行排序        //NSString 自身已经实现了 compare:方法,NSString本身就可以比较大小——NSString比较大小的方法是根据字符对应的编码进行的。        array1 = [array1 sortedArrayUsingSelector:            @selector(compare:)];        NSLog(@"%@" , array1);        // 初始化一个元素为NSNumber的NSArray对象        NSArray* array2 = [NSArray arrayWithObjects:            [NSNumber numberWithInt:20],             [NSNumber numberWithInt:12],             [NSNumber numberWithInt:-8],             [NSNumber numberWithInt:50],             [NSNumber numberWithInt:19], nil];        // 使用intSort函数执行排序              array2 = [array2 sortedArrayUsingFunction:intSort            context:nil];        NSLog(@"%@" , array2);        // 使用代码块对集合元素进行排序        NSArray* array3 = [array2 sortedArrayUsingComparator:            ^(id obj1, id obj2)        {            // 该代码块就是根据集合元素的 intValue进行比较            if ([obj1 intValue] > [obj2 intValue])            {                return NSOrderedDescending;            }            if ([obj1 intValue] < [obj2 intValue])             {                return NSOrderedAscending;            }            return NSOrderedSame;        }];         NSLog(@"%@" , array3);    }}

编译运行结果:

2015-10-03 08:27:34.174 923[1121:26309] (    C,    "C++",    "Objective-C",    Perl,    Python,    Ruby)2015-10-03 08:27:34.176 923[1121:26309] (    "-8",    12,    19,    20,    50)2015-10-03 08:27:34.177 923[1121:26309] (    "-8",    12,    19,    20,    50)

自然排序与定制排序
自然排序:集合元素本身可比较大小,直接利用集合元素比较大小的方法进行排序的方式,称为自然排序。
定制排序:通过比较函数或代码块来指定自定义比较规则的方式,称为定制排序。

使用枚举器遍历 NSArray 集合元素

除了根据数组集合元素的索引来遍历集合元素外,还可以调用NSArray对象的如下2个方法来返回枚举器。
1. objectEnumerator:——返回数组的顺序枚举器。
2. reverseObjectEnumerator:——返回数组的逆序枚举器。

上面的2个方法都返回一个 NSEnumerator 枚举器,该枚举器只包含如下2个方法:
1. allObjects:获取被枚举集合中的所有元素。
2. nextObject:获取被枚举集合中的下一个元素。

一般来说,借助nextObject方法即可对集合元素进行枚举——程序通过不断获取 nextObject 方法的返回值,直到该方法的返回值为 nil 结束循环。

示例程序:

#import <Foundation/Foundation.h>int main(int argc , char * argv[]){    @autoreleasepool{        // 读取前面写入磁盘的文件,用文件内容来初始化NSArray集合        NSArray* array = [NSArray arrayWithContentsOfFile:            @"myFile.txt"];             // 获取NSArray的顺序枚举器        NSEnumerator* en = [array objectEnumerator];        id object;        while(object = [en nextObject])        {            NSLog(@"%@" , object);          }        NSLog(@"------下面逆序遍历------");        // 获取NSArray的逆序枚举器          en = [array reverseObjectEnumerator];        while(object = [en nextObject])        {            NSLog(@"%@" , object);          }    }}

输出结果;

孙悟空宝玉黛玉------下面逆序遍历------黛玉宝玉孙悟空

快速枚举(for …in)

快速枚举(for …in)可以适用(NSArray,NSSet,NSDictionary 等集合)。
快速枚举的语法格式如下:

for (type varName in  collection){    //varName 自动迭代访问每个元素}

其中, type是集合元素的类型,varName是一个形参名,快速枚举自动将集合元素依次赋给该变量。

如果使用快速枚举来遍历 NSDictionary 对象,快速枚举中循环计数器依次代表NSDictionary的每个 key 的值

示例代码:

#import <Foundation/Foundation.h>int main(int argc , char * argv[]){    @autoreleasepool{        // 读取前面写入磁盘的文件,用文件内容来初始化NSArray集合        NSArray* array = [NSArray arrayWithContentsOfFile:            @"myFile.txt"];         for(id object in array)        {            NSLog(@"%@" , object);        }    }}

快速枚举遍历数组集合元素无需获得数组长度,也无须根据索引来访问数组元素。快速枚举的实质是一个 foreach 循环,foreach 循环自动迭代数组的每个元素,每个元素被迭代一次后,foreach 循环自动结束。

可变数组(NSMutableArray)

NSArray是不可变数组,创建成功即不可更改。

NSArray只是保存对象的指针,因此NSArray只保证这些指针变量中的地址不能改变,但指针变量指向的变量是可以改变的。

NSMutableArray是NSArray的子类。代表可变的数组集合。
NSMutableArray新增了如下不同开头的方法:
1. 以 add 开头:——增加集合元素的方法
2. 以 remove 开头:——删除集合元素的方法
3. 以 replace 开头:——替换集合元素的方法
4. 以 sort 开头:——对集合本身排序的方法

NSMutableArray同样提供了前面提到的3中排序方法。与 NSArray 的区别是:NSArray的排序方法是返回一个新的,排好序的NSArray对象,而NSMutableArray的排序方法是集合本身排序。

示例代码:

#import <Foundation/Foundation.h>// 定义一个函数,该函数用于把NSArray集合转换为字符串NSString* NSCollectionToString(NSArray* array){    NSMutableString* result = [NSMutableString         stringWithString:@"["];    for(id obj in array)    {        [result appendString:[obj description]];        [result appendString:@", "];    }    // 获取字符串长度    NSUInteger len = [result length];    // 去掉字符串最后的两个字符    [result deleteCharactersInRange:NSMakeRange(len - 2, 2)];    [result appendString:@"]"];    return result;}int main(int argc , char * argv[]){    @autoreleasepool{        // 读取前面写入磁盘的文件,用文件内容来初始化NSMutableArray集合        NSMutableArray* array = [NSMutableArray            arrayWithContentsOfFile:@"myFile.txt"];         // 向集合最后添加一个元素          [array addObject:@"疯狂iOS讲义"];        NSLog(@"最后追加一个元素后:%@" , NSCollectionToString(array));        // 使用NSArray向集合尾部添加多个元素        [array addObjectsFromArray: [NSArray             arrayWithObjects:@"张飞" , @"关羽",nil]];        NSLog(@"最后追加两个元素后:%@" , NSCollectionToString(array));        // 向集合的指定位置插入一个元素        [array insertObject:@"疯狂Ajax讲义" atIndex:2];        NSLog(@"在索引为2处插入一个元素后:%@"             , NSCollectionToString(array));        // 使用NSArray向集合指定位置插入多个元素        [array insertObjects: [NSArray             arrayWithObjects:@"武松" , @"林冲",nil]             atIndexes:[NSIndexSet indexSetWithIndexesInRange             :NSMakeRange(3,2)]];        NSLog(@"插入多个元素后:%@" , NSCollectionToString(array));         // 删除集合最后一个元素        [array removeLastObject];        NSLog(@"删除最后一个元素后:%@" , NSCollectionToString(array));        // 删除集合中指定索引处的元素        [array removeObjectAtIndex:5];        NSLog(@"删除索引为5处的元素后:%@" , NSCollectionToString(array));        // 删除2~5处元素        [array removeObjectsInRange:NSMakeRange(2, 3)];        NSLog(@"删除索引为2~5处的元素后:%@"             , NSCollectionToString(array));        // 替换索引为2处的元素        [array replaceObjectAtIndex:2 withObject:@"疯狂Android讲义"];        NSLog(@"替换索引为2处的元素后:%@"             , NSCollectionToString(array));    }}

NSArray的 kvc 与 kvo

NSArray允许直接对集合中的所有元素进行整体的 KVC 编码。NSArray提供了 下面2个方法(用途见示例代码) :
1. valueForKey:——拿key 对应属性或实例变量,设置为value。
2. setValue: forKey:

示例代码:

#import <Foundation/Foundation.h>#import "FKUser.h"// 定义一个函数,该函数用于把NSArray集合转换为字符串NSString* NSCollectionToString(NSArray* array){    NSMutableString* result = [NSMutableString         stringWithString:@"["];    for(id obj in array)    {        [result appendString:[obj description]];        [result appendString:@", "];    }    // 获取字符串长度    NSUInteger len = [result length];    // 去掉字符串最后的两个字符    [result deleteCharactersInRange:NSMakeRange(len - 2, 2)];    [result appendString:@"]"];    return result;}int main(int argc , char * argv[]){    @autoreleasepool{        // 初始化NSArray对象        NSArray* array = [NSArray arrayWithObjects:            [[FKUser alloc] initWithName:@"sun" pass:@"123"],            [[FKUser alloc] initWithName:@"bai" pass:@"345"],            [[FKUser alloc] initWithName:@"zhu" pass:@"654"],            [[FKUser alloc] initWithName:@"tang" pass:@"178"],            [[FKUser alloc] initWithName:@"niu" pass:@"155"],            nil];        // 获取所有集合元素的name属性组成的新集合        id newArr = [array valueForKey:@"name"];        NSLog(@"%@" , NSCollectionToString(newArr));        // 对集合中所有元素整体进行KVC编程        // 将所有集合元素的name属性改为"新名字"        [array setValue:@"新名字" forKey:@"name"];        NSLog(@"%@" , NSCollectionToString(array));    }}

kvo

NSArray还为集合中的所有 元素或者部分元素 进行 KVO 编程提供了如下主要方法(其他方法可以自己尝试 ):
1. addObserver: forKeyPath: options: context:为集合中是所有元素 添加 KVO 监听器。
2. addObserver: toObjectsAtIndexes: forKeyPath: options: context: :为集合中指定索引处的 元素添加KVO 监听器。
3. removeObserver: forKeyPath: 为集合中是所有元素删除 KVO 监听器
4. removeObserver: fromObjectsAtIndexes: forKeyPath: :为集合中指定索引处的 元素删除KVO 监听器。

0 0
原创粉丝点击