您的位置:首页 > 移动开发 > Objective-C

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

2015-10-03 10:23 591 查看
数组代表元素有序,可重复的一个集合,集合中每个元素都有其对应的顺序索引。索引值从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 监听器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息