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

数组代表元素有序,可重复的一个集合,集合中每个元素都有其对应的顺序索引。索引值从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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值