iOS学习笔记-02集合

2.集合

  • 集合分为可变与不可变。

  • 泛型,写法NSMutableArray<NSNumber*>* mutablearr = [NSMutableArray array];NSMutableDictionary<NSString*, NSNumber*>* dic = [[NSMutableDictionary alloc] init];,目前会有warning提示如果类型不对。多参数泛型如下,第二行为Xcode的提示性代码。

    1
    2
    NSMutableDictionary<NSString*, NSNumber*>* dic = [[NSMutableDictionary alloc] init];
    [dic addEntriesFromDictionary:<#(nonnull NSDictionary<NSString *,NSNumber *> *)#>]

目前来看类型只能是Objective-C object或者block。

  1. NSArray特点: 一旦创建成功,内容不可改变,只能存放OC对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//1)创建一个空数组
NSArray *arr1 = [NSArray array];

//2)创建数组,只有一个元素
NSArray *arr2 = [NSArray arrayWithObject:@"1"];

//3)创建数组,有多个元素
// nil 表示数组赋值结束
// 常见写法
NSArray *arr3 = [NSArray arrayWithObjects:@"one",@"two",@1, nil];
NSLog(@"arr3 = %@",arr3);
//4)调用对象方法,创建数组
//nil Nil NULL NSNULL
NSArray *arr4 = [[NSArray alloc] initWithObjects:@"three",[NSNull null],@"four", nil];
NSLog(@"arr4 = %@",arr4);
//5)用一个数组可以创建另外一个数组,修改一个数组中的数据不影响另一个数组。
NSArray *arr5 = [NSArray arrayWithArray:arr3];
  1. 常用方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
NSArray* arr3 = [NSArray arrayWithObjects:@"one", @"two", @1, @"three", nil];
NSLog(@"arr3 = %@", arr3);

//1)获取数组的长度 count获取数组的元素的个数
NSLog(@"%ld", arr3.count);

//2)根据下标,获取下标对应的对象
NSLog(@"%@", [arr3 objectAtIndex:3]);

//3)返回元素的下标
NSUInteger loc = [arr3 indexOfObject:@"three"];
NSLog(@"%ld", loc);

//4)数组中是否包含了某个元素
if ([arr3 containsObject:@"four"]) {

NSLog(@"包含此元素");
}
else {

NSLog(@"不包含");
}
NSLog(@"arr5 = %@", arr5);
  1. 简化形式
1
2
3
4
5
6
7
8
9
10
11
12
//用简化的方式,来定义和访问数组元素
//1)用简化的方式,定义数组
//格式: @[ 数组元素 ]
NSArray* arr = @[ @"1", @"one", @"3", @4, @"ONE" ];
NSLog(@"arr = %@", arr);

NSString* str = [arr objectAtIndex:2];
NSLog(@"%@", str);

//2)用简化的方式访问数组元素
str = arr[1]; //C语言形式的数组元素访问
NSLog(@"%@", str);
  1. 遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
   //定义一个数组
NSArray* arr = @[ @"one", @"two", @"three", @"four" ];

//对数组进行遍历

//1) 普通的方式,通过下标访问
for (int i = 0; i < arr.count; i++) {
NSLog(@"-> %@", arr[i]);
}

//2) 快速枚举法 for循环的增强形式
for (NSString* str in arr) {
NSLog(@"---> %@", str);
}

//3) 使用block的方式,进行访问
// 数组元素 元素下标 是否停止
//stop:YES 会停止, stop:NO 不会停止
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop) {

if (idx == 2) {

*stop = YES; //停止 // break;
}
else {

NSLog(@"idx = %ld,obj = %@", idx, obj);
}

}];

//补充:OC1.0中的方法
id obj2;
NSEnumerator* enumerator = [arr objectEnumerator];
while ((obj2 = [enumerator nextObject]) != nil) {
NSLog(@"%@ ", obj2);
}
```

5. 读写文件:

- 写入

NSArray* array = [NSArray arrayWithObjects:@”one”, @”zbz”, @”cgx”, @”sb”, @”cjk”, @”senni”, nil];
//把NSArray 中的内容,写入到文件中
//arr.plist 一种特殊的文件格式
BOOL isWrite = [array writeToFile:@”/Users/zhaoxiaohu/Desktop/arr.xml” atomically:YES];

if (isWrite) {
    NSLog(@"写入成功");
}
1
2

- 读取

//从文件中,读取一个数组信息
NSArray *readArr = [NSArray arrayWithContentsOfFile:@”/Users/zhaoxiaohu/Desktop/arr.xml”];

NSLog(@”readArr = %@”,readArr);

1
2
3
4
  
6. NSArray与字符串:

- 把数组拼接成为字符串

//定义一个数组
NSArray *arr = @[@1,@2,@3,@4];

//1)需求: 把数组中的元素用 “-“ 连接起来
// [数组 componentsJoinedByString @”分隔符”];
// 1-2-3-4
NSString *str = [arr componentsJoinedByString:@”-“];
NSLog(@”str = %@”,str);

1
2
 
- 把字符串拆分为数组

//2) 给一个字符串,分割成一个数组
// 400-800-12580 //取得 400 12580 800
NSString *str2 = @”400-800-12580”;
NSArray *arr2 = [str2 componentsSeparatedByString:@”-“];
NSLog(@”%@”,[arr2 firstObject]);
NSLog(@”%@”,[arr2 lastObject]);
NSLog(@”%@”,arr2[1]);

1
2
3
4
5
6
7
8
 
- #### NSMutableArray

- NSArray子类,内容可变,其余很多操作与NSArray一样。

```
NSMutableArray<NSNumber*>* mutablearr = [NSMutableArray array];
[mutablearr addObject:[NSNumber numberWithInt:1]];

  • 虽然有arrayWithCapacity这个方法,但是内容是可以超出设定的值的。应该仅仅是申请内存的需要,毕竟可变长度对于内存操作上比较麻烦。
  • NSDictionary与NSMutableDictionary

    字典的核心在于key和value。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//创建字典
//1、使用类方法创建字典
// 字典初始化后,内部是无序的
NSDictionary* dict1 = [NSDictionary dictionaryWithObjectsAndKeys:@"zhangsan", @"zs", @"lisi", @"ls", nil];

//获取字典的长度
NSLog(@"%ld", dict1.count);
//根据key获取 value 只获取zs
NSString* s = [dict1 objectForKey:@"zs"];
NSLog(@"%@", s);

//2、快速创建字典 @{key:value,key1:value1}
// 在字典中,key值是不能够重复的,重复的时候不会报错
// 重复的只保留一个(第一次出现的那个)
NSDictionary* dict2 = @{ @"zs" : @"zhangsan",
@"ls" : @"lisi",
@"zs" : @"fengjie" };
NSLog(@"%@", dict2);

//3、遍历

NSLog(@"获取所有keys的遍历");
NSArray* keys = [dict2 allKeys];
for (NSInteger i = 0; i < keys.count; i++) {
NSLog(@"key = %@ value = %@", (NSString*)keys[i], [dict2 objectForKey:keys[i]]);
}

NSLog(@"NSEnumerator遍历");
id key;
NSEnumerator* enumerator = [dict2 keyEnumerator];
while ((key = [enumerator nextObject]) != nil) {
NSLog(@"key = %@ value = %@", (NSString*)key, [dict2 objectForKey:key]);
}

NSLog(@"快速遍历");
for (id key in dict2) {
NSLog(@"key = %@ value = %@", (NSString*)key, dict2[key]);
}

NSLog(@"block遍历");

[dict2 enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL* _Nonnull stop) {
NSLog(@"key = %@ value = %@", key, obj);
}];

//4、可变的字典
NSMutableDictionary* mDic = [NSMutableDictionary dictionaryWithDictionary:dict1];

//4.1 移除数据
[mDic setValue:nil forKey:@"zs"];
[mDic removeObjectForKey:@"ls"];
[mDic removeAllObjects];
// [mDic removeObjectForKey:<#(nonnull id)#>];

//4.2 添加数据
[mDic setObject:@"wei" forKey:@"hua"];
[mDic setValue:@"xing" forKey:@"zhong"];
//4.3 改变数据
[mDic setObject:@"lisi2222" forKey:@"ls"];

NSLog(@"遍历NSMutableDictionary");
[mDic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL* _Nonnull stop) {
NSLog(@"key = %@ value = %@", key, obj);
}];

注意setValue:forKey:这个方法,既可以添加数据也可以移除数据(当value是nil时)。

1
2
3
  /* Send -setObject:forKey: to the receiver, unless the value is nil, in which case send -removeObjectForKey:.
*/
- (void)setValue:(nullable ObjectType)value forKey:(NSString *)key;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
在Foundation框架中,提供了NSSet类,它是一组单值对象的集合,且NSSet实例中元素是无序,同一个对象只能保存一个。

一.不可变集合NSSet

1.NSSet的初始化

创建一个集合

NSSet *set1 = [[NSSet alloc] initWithObjects:@"one", @"two", nil];

通过数组的构建集合

NSArray *array = [NSArrayWithObjects:@"1", @"2", @"3", nil];

NSSet *set2 = [[NSSet alloc] initWithArray:array];

通过已有集合构建集合

NSSet *set3 = [[NSSet alloc] initWithSet:set2];

2.NSSet常用方法

集合中对象的个数

int count = [set3 count];

以数组的形式返回集合中所有的对象

NSArray *allObjects = [set3 allObjects];

返回集合中的任意一个对象

id object = [set3 anyObject];

判断两个集合的元素中有包含的对象,包含返回YES,否则为NO

BOOL isContain = [set4 containsObject:@"2"];

判断两个集合的元素是否有相等的对象,存在返回YES,否则为NO

BOOL isIntersect = [set4 intersectsSet:set2];

判断两个集合的元素是否完全匹配,匹配返回YES,否则为NO

BOOL isEqual = [set4 isEqualToSet:set5];

集合4是否是集合5的子集合,如果是返回YES,否则为NO

BOOL isSubset = [set4 isSubsetOfSet:set5];

创建一个新的集合2,集合2有两个对象

NSSet *set1 = [NSSet setWithObjects:@"a",nil];

NSSet *set2 = [set1 setByAddingObject:@"b"];

通过已有的两个集合,创建新的一个集合

NSSet *set7 = [NSSet setWithObjects:@"a",nil];

NSSet *set8 = [NSSet setWithObjects:@"z",nil];

NSSet *set9 = [set7 setByAddingObjectsFromSet:set8];

通过已有的集合和数组对象,创建一个新的集合

NSArray *array = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];

NSSet *set10 = [NSSet setWithObjects:@"z",nil];

NSSet *set11 = [set10 setByAddingObjectsFromArray:array];

二、可变集合NSMutableSet

常用方法

创建一个空的集合

NSMutableSet *set1 = [NSMutableSet set];

NSMutableSet *set2 = [NSMutableSet setWithObjects:@"1",@"2",nil];

NSMutableSet *set3 = [NSMutableSet setWithObjects:@"a",@"2",nil];

集合2减去集合3中的元素,集合2最后元素只有1个

[set2 minusSet:set3];

集合2与集合3中元素的交集,集合2最后元素只有1个

[set2 intersectSet:set3];

集合2与集合3中的元素的并集,集合2最后元素只有3个

[set2 unionSet:set3];

将空集合1设置为集合3中的内容

[set1 setSet:set3];

根据数组的内容删除集合中的对象

[set2 addObjectsFromArray:array];

[set2 removeObject:@"1"];

[set]2 removeAllObjects];
  • 关于遍历

    • 从NSArray的遍历中就可以看出目前基本有四种遍历方法,分别是for、快速遍历,OC1.0的Enumerator方法和block遍历。
    • 对于这四种遍历来说,block应该是通用性最好的。NSArray往往需要下标值,而dictionary需要key和value,NSSet只是需要内容。对于不同的需求来说,前三个方法没有通用性。block方法为不同的集合有不同的实现方法,enumerateObjectsUsingBlockenumerateKeysAndObjectsUsingBlock,而且提供了类似enumerateKeysAndObjectsWithOptions这样的方法,可以选择是反序遍历或者并发遍历。
  • 关于NSNumber

    在使用数组和字典时会发现其内容不能使用简单类型,比如int,float,bool类型等,此时就需要用到NSNumber了,通过转换保存数值到数组或者字典。当然也可以通过@1这样的形式来讲数值保存到数字或字典。

1
2
3
4
NSMutableArray* mutablearr = [NSMutableArray arrayWithArray:@[ @9, @8 ]];
[mutablearr addObject:[NSNumber numberWithInt:1]];
[mutablearr addObject:[NSNumber numberWithInt:2]];
[mutablearr addObject:@1];
  • NSCache

    缓存应该选择的数据类型,dictionary和array在iOS中并不是很好的缓存选择,更好的选择应该是NSCache。原因如下:

    1.对于键值是retain而不是copy,这个是很dictionary本质的区别。

    2.线程安全,支持多线程操作。

    3.自己实现了很多控制性的功能,比如对象的多少,最大存储量(但是limits are imprecise/not strict,逗比!!!),在内存不足(didReceiveMemoryWarning)时可以自动的删除,并且按照优先删除最久未使用的对象。

    参考

  • NSUserDefaults 原文

    • 了解NSUserDefaults以及它可以直接存储的类型

      NSUserDefaults是一个单例,在整个程序中只有一个实例对象,他可以用于数据的永久保存,而且简单实用,这是它可以让数据自由传递的一个前提,也是大家喜欢用它保存简单数据的一个主要原因。

      使用 NSUserDefaults 存储自定义对象的最初,我们必须认识NSUserDefaults可以存储哪一些类型的数据,下面一一列出:

      NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.

      如果想要将上述数据类型的数据永久保存到NSUserDefaults中去,只需要简单的操作(一个Value 一个Key ),例如,想要保存一个NSString的对象,代码实现为:

1
2
3
4
5
6
7
8
9
10
//将NSString 对象存储到 NSUserDefaults 中
NSString *passWord = @"1234567";
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:passWord forKey:@"userPassWord"];


将数据取出也很简单,只需要取出key 对应的值就好了,代码如下:

NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *passWord = [ user objectForKey:@"userPassWord"];

注意:对相同的Key赋值约等于一次覆盖,要保证每一个Key的唯一性

<font color=red>值得注意的是:</font>
NSUserDefaults 存储的对象<font color=red>全是不可变的</font>
(这一点非常关键,弄错的话程序会出bug),例如,如果我想要存储一个 NSMutableArray 对象,我必须先创建一个不可变数组(NSArray)再将它存入NSUserDefaults中去,代码如下:
1
2
3
4
5
NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"123",@"234", nil];
NSArray * array = [NSArray arrayWithArray:mutableArray];

NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:array forKey:@"记住存放的一定是不可变的"];
取出数据是一样的,想要用NSUserDefaults中的数据给可变数组赋值

先给出一个错误的写法:
1
2
3
4
5
/*-------------------------错误的赋值方法-------------------*/
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

//这样写后,mutableArray 就变成了不可变数组了,如果你要在数组中添加或删除数据就会出现bug
NSMutableArray *mutableArray = [user objectForKey:@"记住存放的一定是不可变的"];
正确的写法:
1
2
3
4
5
/*-------------------------正确的赋值方法-------------------*/
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

//可以用alloc 方法代替
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:[user objectForKey:@"记住存放的一定是不可变的"]];
  • 使用 NSUserDefaults 存储自定义对象

    1、将自定义类型转换为NSData类型

    当数据重复而且多的时候(例如想存储全班同学的学号,姓名,性别(这个数据量可能太大了 )),如果不用SQLite 存储 (多数据最好还是用这个),你可以选择使用归档,再将文件写入本地,但是这种方式和 NSUserDefaults 比起来麻烦多了(因为NSFileManage 本来就挺复杂) ,但是问题是,NSUserDefaults 本身不支持自定义对象的存储,不过它支持NSData的类型,下面举一个例子来介绍。
我们先建立一个叫Student 的类,这个类里有三个属性(学号,姓名,性别),如图:

![](http://images2015.cnblogs.com/blog/23250/201610/23250-20161003181834145-1260516689.png)

我们要做的就是将Student类型变成NSData类型 ,那么就必须实现归档:

这里要实现 在.h 文件中申明 NSCoding 协议,再 在 .m 中实现 encodeWithCoder 方法 和 

initWithCoder 方法就可以了 : 

.h 中修改文件如图 :

![](http://images2015.cnblogs.com/blog/23250/201610/23250-20161003181857239-402489604.jpg)

.m中加入代码 :

![](http://images2015.cnblogs.com/blog/23250/201610/23250-20161003181907192-668738465.png)

这样做就可以将自定义类型转变为NSData类型了



2、将自定义类型数据存入 NSUserDefaults 中

 如果要存储全班同学的信息,我们可以建一个NSMutableArray 来存放全班同学的信息(里面存储的全是NSData对象)在需要存储的地方加入代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
//首先,要建立一个可变数组来存储 NSDate对象
Student* student = [[Student alloc] ini];
//下面进行的是对student对象的 name , studentNumber ,sex 的赋值
student.name = @"lady-奕奕";
student.studentNumber = @"3100104006";
student.sex = @"女";

//这是一个存放全班同学的数组
NSMutableArray* dataArray = [NSMutableArray arrayWithCapacity:50];
//将student类型变为NSData类型
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:student];
//存放数据的数组将data加入进去
[dataArray addObject:data];

如果你只想存一个人的信息,你可以直接将NSData存入NSUserDefaults中 :

1
2
3
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];   
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"oneStudent"];

如果你想存储全班同学的信息,你还要用一个for循环将data 放入 dataArray中,这里具体的操作就不实现了,只给出存放的代码:

1
2
3
4
//记住要转换成不可变数组类型
NSArray * array = [NSArray arrayWithArray:dataArray];
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:array forKey:@"allStudent"];

从NSUserDefaults中取出数据在还原也很简单。例如还原一个学生的数据:

1
2
3
4
5
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

NSdData *data = [user objectForKey:@"oneStudent"];

Student *student = [NSKeyedUnarchiver unarchiveObjectWithData:data];
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×