iOS学习笔记-02集合

Posted by 蔡华的博客 on September 16, 2016

2.集合

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

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

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

<font color=red>目前来看类型只能是Objective-C object或者block。</font>

  1. NSArray特点: 一旦创建成功,内容不可改变,只能存放OC对象。
   //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. 常用方法:
   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)用简化的方式,定义数组
   //格式: @[ 数组元素 ]
   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. 遍历
   //定义一个数组
    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);
    }
  1. 读写文件:
  • 写入
   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(@"写入成功");
    }
    
  • 读取
   //从文件中,读取一个数组信息
  NSArray *readArr = [NSArray arrayWithContentsOfFile:@"/Users/zhaoxiaohu/Desktop/arr.xml"];

  NSLog(@"readArr = %@",readArr);
  1. NSArray与字符串:
  • 把数组拼接成为字符串
 //定义一个数组
  NSArray *arr = @[@1,@2,@3,@4];

  //1)需求: 把数组中的元素用 "-" 连接起来
  //  [数组 componentsJoinedByString @"分隔符"];
  // 1-2-3-4
  NSString *str = [arr componentsJoinedByString:@"-"];
  NSLog(@"str = %@",str);
  • 把字符串拆分为数组
  //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]);
 ```
 
- #### NSMutableArray	 
 
 - NSArray子类,内容可变,其余很多操作与NSArray一样。
  

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

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

 字典的核心在于key和value。
   

//创建字典 //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时)。

  /* Send -setObject:forKey: to the receiver, unless the value is nil, in which case send -removeObjectForKey:.
*/
- (void)setValue:(nullable ObjectType)value forKey:(NSString *)key;
	 在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这样的形式来讲数值保存到数字或字典。

    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的对象,代码实现为:

	//将NSString 对象存储到 NSUserDefaults 中
	NSString *passWord = @"1234567";
	NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
	[user setObject:passWord forKey:@"userPassWord"];
	
	
	将数据取出也很简单,只需要取出key 对应的值就好了,代码如下:
	
	NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
	NSString *passWord = [ user objectForKey:@"userPassWord"];

<font color=red>注意:对相同的Key赋值约等于一次覆盖,要保证每一个Key的唯一性</font>

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

先给出一个错误的写法:
	    /*-------------------------错误的赋值方法-------------------*/
	    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
	    
	    //这样写后,mutableArray 就变成了不可变数组了,如果你要在数组中添加或删除数据就会出现bug
	    NSMutableArray *mutableArray = [user objectForKey:@"记住存放的一定是不可变的"];
正确的写法:
	    /*-------------------------正确的赋值方法-------------------*/
	    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
	    
	    //可以用alloc 方法代替
	    NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:[user objectForKey:@"记住存放的一定是不可变的"]];
  • 使用 NSUserDefaults 存储自定义对象

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

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

    我们先建立一个叫Student 的类,这个类里有三个属性(学号,姓名,性别),如图:

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

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

    initWithCoder 方法就可以了 :

    .h 中修改文件如图 :

    .m中加入代码 :

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

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

    如果要存储全班同学的信息,我们可以建一个NSMutableArray 来存放全班同学的信息(里面存储的全是NSData对象)在需要存储的地方加入代码:

	//首先,要建立一个可变数组来存储 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中 :

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

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

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

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

	NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
	 
	NSdData *data = [user objectForKey:@"oneStudent"];
	    
	Student *student = [NSKeyedUnarchiver unarchiveObjectWithData:data];