-----------android培训、java培训、IOS学习型技术博客、期待与您交流!------------
可变数组
下面看一下可变数组的内容:
// // main.m // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> #import "Person.h" void test1(){ Person *person1=[Person personWithName:@"Kenshin"]; Person *person2=[Person personWithName:@"Kaoru"]; Person *person3=[Person personWithName:@"Rosa"]; NSMutableArray *array1=[NSMutableArray arrayWithObjects:person1,person2,person3, nil]; NSLog(@"%@",array1); /*结果: ( "name=Kenshin", "name=Kaoru", "name=Rosa" ) */ Person *person4=[Person personWithName:@"Jack"];//此时person4的retainCount为1 [array1 addObject:person4];//添加一个元素,此时person4的retainCount为2 NSLog(@"%@",array1); /*结果: ( "name=Kenshin", "name=Kaoru", "name=Rosa", "name=Jack" ) */ [array1 removeObject:person3];//删除一个元素 NSLog(@"%@",array1); /*结果: ( "name=Kenshin", "name=Kaoru", "name=Jack" ) */ [array1 removeLastObject];//删除最后一个元素,//此时person4的retainCount为1 NSLog(@"%@",array1); /*结果: ( "name=Kenshin", "name=Kaoru" ) */ [array1 removeAllObjects];//删除所以元素 //注意当往数组中添加一个元素时会retain因此计数器+1,当从数组中移除一个元素时会release因此计数器-1 //当NSMutalbeArray对象release的时候会依次调用每一个对象的release } void test2(){ NSMutableArray *array1=[NSMutableArray arrayWithObjects:@"1",@"3",@"2", nil]; NSLog(@"%@",array1); /*结果: ( 1, 3, 2 ) */ NSArray *array2= [array1 sortedArrayUsingSelector:@selector(compare:)];//注意这个方法没有修改array1 NSLog(@"%@",array1); /*结果: ( 1, 3, 2 ) */ NSLog(@"%@",array2); /*结果: ( 1, 2, 3 ) */ [array1 sortUsingSelector:@selector(compare:)];//这个方法会修改array1 NSLog(@"%@",array1); /*结果: ( 1, 2, 3 ) */ } int main(int argc, const char * argv[]) { test1(); test2(); return 0; }
- 可变数组中的元素后面必须加nil以表示数据结束;
- 往一个可变数组中添加一个对象,此时这个对象的引用计数器会加1,当这个对象从可变数组中移除其引用计数器减1。同时当整个数组销毁之后会依次调用每个对象的releaes方法。
- 在不可变数组中无论对数组怎么排序,原来的数组顺序都不会改变,但是在可变数组中如果使用sortUsingSelector:排序原来的数组顺序就发生了变化。
// // main.m // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> void test1(){ NSDictionary *dic1=[NSDictionary dictionaryWithObject:@"1" forKey:@"a"]; NSLog(@"%@",dic1); /*结果: { a = 1; } */ //常用的方式 NSDictionary *dic2=[NSDictionary dictionaryWithObjectsAndKeys: @"1",@"a", @"2",@"b", @"3",@"c", nil]; NSLog(@"%@",dic2); /*结果: { a = 1; b = 2; c = 3; } */ NSDictionary *dic3=[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1",@"2", nil] forKeys:[NSArray arrayWithObjects:@"a",@"b", nil]]; NSLog(@"%@",dic3); /*结果: { a = 1; b = 2; } */ //更简单的方式 NSDictionary *dic4=@{@"1":@"a",@"2":@"b",@"3":@"c"}; NSLog(@"%@",dic4); /*结果: { 1 = a; 2 = b; 3 = c; } */ } void test2(){ NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys: @"1",@"a", @"2",@"b", @"3",@"c", @"2",@"d", nil]; NSLog(@"%zi",[dic1 count]); //结果:4 NSLog(@"%@",[dic1 valueForKey:@"b"]);//根据键取得值,结果:2 NSLog(@"%@",dic1[@"b"]);//还可以这样读取,结果:2 NSLog(@"%@,%@",[dic1 allKeys],[dic1 allValues]); /*结果: ( d, b, c, a ),( 2, 2, 3, 1 ) */ NSLog(@"%@",[dic1 objectsForKeys:[NSArray arrayWithObjects:@"a",@"e" , nil]notFoundMarker:@"not fount"]);//后面一个参数notFoundMarker是如果找不到对应的key用什么值代替 /*结果: ( 1, "not fount" ) */ } void test3(){ NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys: @"1",@"a", @"2",@"b", @"3",@"c", @"2",@"d", nil]; //遍历1 for (id key in dic1) { NSLog(@"%@=%@",key,[dic1 objectForKey:key]); } /*结果: d=2 b=2 c=3 a=1 */ //遍历2 NSEnumerator *enumerator=[dic1 keyEnumerator]; id key=nil; while (key=[enumerator nextObject]) { NSLog(@"%@=%@",key,[dic1 objectForKey:key]); } /*结果: d=2 b=2 c=3 a=1 */ //遍历3 [dic1 enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { NSLog(@"%@=%@",key,obj); }]; /*结果: d=2 b=2 c=3 a=1 */ } void test4(){ NSMutableDictionary *dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:@"1",@"a", @"2",@"b", @"3",@"c", @"2",@"d", nil]; [dic removeObjectForKey:@"b"]; NSLog(@"%@",dic); /*结果: { a = 1; c = 3; d = 2; } */ [dic addEntriesFromDictionary:@{@"e":@"7",@"f":@"6"}]; NSLog(@"%@",dic); /*结果: { a = 1; c = 3; d = 2; e = 7; f = 6; } */ [dic setValue:@"5" forKey:@"a"]; NSLog(@"%@",dic); /*结果: { a = 5; c = 3; d = 2; e = 7; f = 6; } */ } int main(int argc, const char * argv[]) { test1(); test2(); test3(); test4(); return 0; }
对象拷贝操作也比较常见,在ObjC中有两种方式的拷贝:copy和mutablecopy,这两种方式都将产生一个新的对象,只是后者产生的是一个可变对象。在ObjC中如果要想实现copy或者mutablecopy操作需要实现NSCopy或者NSMutableCopy协议,拷贝操作产生的新的对象默认引用计数器是1,在非ARC模式下我们应该对这个对象进行内存管理。在熟悉这两种操作之前我们首先需要弄清两个概念:深复制(或深拷贝)和浅复制(或浅拷贝)。
- 浅复制:在执行复制操作时,对于对象中每一层(对象中包含的对象,例如说属性是某个对象类型)复制都是指针复制(如果从引用计数器角度出发,那么每层对象的引用计数器都会加1)。
- 深复制:在执行复制操作时,至少有一个对象的复制是对象内容复制(如果从引用计数器角度出发,那么除了对象内容复制的那个对象的引用计数器不变,其他指针复制的对象其引用计数器都会加1)
对比copy和mutablecopy其实前面我们一直还用到一个操作是retain,它们之间的关系如下:
retain:始终采取浅复制,引用计数器会加1,返回的对象和被复制对象是同一个对象1(也就是说这个对象的引用多了一个,或者说是指向这个对象的指针多了一个);
copy:对于不可变对象copy采用的是浅复制,引用计数器加1(其实这是编译器进行了优化,既然原来的对象不可变,复制之后的对象也不可变那么就没有必要再重新创建一个对象了);对于可变对象copy采用的是深复制,引用计数器不变(原来的对象是可变,现在要产生一个不可变的当然得重新产生一个对象);
mutablecopy:无论是可变对象还是不可变对象采取的都是深复制,引用计数器不变(如果从一个不可变对象产生一个可变对象自然不用说两个对象绝对不一样肯定是深复制;如果从一个可变对象产生出另一个可变对象,那么当其中一个对象改变自然不希望另一个对象改变,当然也是深复制).
// // main.m // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> void test1(){ NSString *name=@"Kenshin"; NSString *str1=[NSString stringWithFormat:@"I'm %@.",name];//注意此时str1的计数器是1 NSLog(@"%lu",[str1 retainCount]); //结果:1 NSMutableString *str2=[str1 mutableCopy];//注意此时str2的计数器为1,str1的计数器还是1 //NSMutableString *str5 =CFRetain((__bridge CFTypeRef)str2); NSLog(@"retainCount(str1)=%lu,retainCount(str2)=%lu",[str1 retainCount],[str2 retainCount]); //结果:retainCount(str1)=1,retainCount(str2)=1 [str2 appendString:@"def"];//改变str2,str1不变 NSLog(@"%zi",str1==str2);//二者不是向同一个对象,结果:0 NSLog(@"str1=%@",str1); //结果:str1=I'm Kenshin. NSLog(@"str2=%@",str2); //结果:str2=I'm Kenshin.def NSLog(@"str1's %lu",[str1 retainCount]); NSString *str3=[str1 copy];//str3不是产生的新对象而是复制了对象指针,但是str1的计数器+1(当然既然str3同样指向同一个对象,那么如果计算str3指向的对象引用计数器肯定等于str1的对象引用计数器) NSLog(@"%zi",str1==str3);//二者相等指向同一个对象,结果:1 NSLog(@"retainCount(str1)=%lu,retainCount(str3)=%lu",str1.retainCount,str3.retainCount); //结果:retainCount(str1)=2,retainCount(str3)=2 //需要注意的是使用copy和mutableCopy是深复制还是浅复制不是绝对,关键看由什么对象产生什么样的对象 NSString *str4=[str2 copy];//由NSMutableString产生了NSString,二者类型都不同肯定是深拷贝,此时str2的计数器还是1,str4的计数器也是1 [str2 appendString:@"g"];//改变原对象不影响str4 NSLog(@"%zi",str2==str4); //结果:0 NSLog(@"str2=%@",str2); //结果:str2=I'm Kenshin.defg NSLog(@"str4=%@",str4); //结果:str4=I'm Kenshin.def [str1 release]; str1=nil; [str3 release];//其实这里也可以调用str1再次release,因为他们两个指向的是同一个对象(但是一般不建议那么做,不容易理解) str3=nil; [str2 release]; str2=nil; [str4 release]; str4=nil; //上面只有一种情况是浅拷贝:不可变对象调用copy方法 } int main(int argc,char *argv[]){ test1(); return 0; }
要想支持copy或者mutablecopy操作那么对象必须实现NSCoping协议并实现-(id)copyWithZone:(NSZone*)zone方法,在Foundation中常用的可复制对象有:NSNumber、NSString、NSMutableString、NSArray、NSMutableArray、NSDictionary、NSMutableDictionary。下面看一下如何让自定义的类支持copy操作:
Person.h
// // Person.h // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> @class Account; @interface Person : NSObject @property NSMutableString *name; @property (nonatomic,assign) int age; @end
Person.m
// // Person.m // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import "Person.h" @implementation Person -(NSString *)description{ return [NSString stringWithFormat:@"name=%@,age=%i",_name,_age]; } //实现copy方法 -(id)copyWithZone:(NSZone *)zone{ //注意zone是系统已经分配好的用于存储当前对象的内存 //注意下面创建对象最好不要用[[Person allocWithZone:zone]init],因为子类如果没有实现该方法copy时会调用父类的copy方法,此时需要使用子类对象初始化如果此时用self就可以表示子类对象,还有就是如果子类调用了父类的这个方法进行重写copy也需要调用子类对象而不是父类Person Person *person1=[[[self class] allocWithZone:zone]init]; person1.name=_name; person1.age=_age; return person1; } @end
main.m
// // main.m // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> #import "Account.h" #import "Person.h" void test1(){ Person *person1=[[Person alloc]init]; NSMutableString *str1=[NSMutableString stringWithString:@"Kenshin"]; person1.name=str1; //由于name定义的时候使用属性参数采用的是copy策略,而根据前面的知识我们知道NSMutableString的copy策略采用的是对象内容复制,因此如果修改str1不会改变person1.name [str1 appendString:@" Cui"]; NSLog(@"%@",str1);//结果:Kenshin Cui NSLog(@"%@",person1.name); //结果:Kenshin } void test2(){ Person *person1=[[Person alloc]init]; person1.name=[NSMutableString stringWithString:@"Kenshin"]; person1.age=28; Person *person2=[person1 copy]; NSLog(@"%@",person1); //结果:name=Kenshin,age=0 NSLog(@"%@",person2); //结果:name=Kenshin,age=0 [person2.name appendString:@" Cui"]; NSLog(@"%@",person1);//结果:name=Kenshin Cui,age=28 NSLog(@"%@",person2);//结果:name=Kenshin Cui,age=28 } int main(int argc,char *argv[]){ test1(); test2(); return 0; }
在上面的代码中重点说一下test2这个方法,在test2方法中我们发现当修改了person2.name属性之后person1.name也改变了,这是为什么呢?我们可以看到在Person.m中自定义实现了copy方法,同时实现了一个浅拷贝。之所以说是浅拷贝主要是因为我们的name属性参数是直接赋值完成的,同时由于name属性定义时采用的是assign参数(默认为assign),所以当通过copy创建了person2之后其实person2对象的name属性和person1指向同一个NSMutableString对象
Person.h
// // Person.h // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> @interface Person : NSObject<NSCoding> @property (nonatomic,copy) NSString *name; @property (nonatomic,assign) int age; @property (nonatomic,assign) float height; @property (nonatomic,assign) NSDate *birthday; @end
Person.m
// // Person.m // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import "Person.h" @implementation Person #pragma mark - -(id)initWithCoder:(NSCoder *)aDecoder{ NSLog(@"decode..."); if (self=[super init]) { self.name=[aDecoder decodeObjectForKey:@"name"]; self.age=[aDecoder decodeInt64ForKey:@"age"]; self.height=[aDecoder decodeFloatForKey:@"heiht"]; self.birthday=[aDecoder decodeObjectForKey:@"birthday"]; } return self; } #pragma mark - -(void)encodeWithCoder:(NSCoder *)aCoder{ NSLog(@"encode..."); [aCoder encodeObject:_name forKey:@"name"]; [aCoder encodeInt64:_age forKey:@"age" ]; [aCoder encodeFloat:_height forKey:@"height"]; [aCoder encodeObject:_birthday forKey:@"birthday"]; } #pragma mark - -(NSString *)description{ NSDateFormatter *formater1=[[NSDateFormatter alloc]init]; formater1.dateFormat=@"yyyy-MM-dd"; return [NSString stringWithFormat:@"name=%@,age=%i,height=%.2f,birthday=%@",_name,_age,_height,[formater1 stringFromDate:_birthday]]; } @end
main.m
// // main.m // FoundationFramework // // Created by Kenshin Cui on 15-9-18. // Copyright (c) 2015年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> #import "Person.h" int main(int argc,char *argv[]){ Person *person1=[[Person alloc]init]; person1.name=@"Kenshin"; person1.age=28; person1.height=1.72; NSDateFormatter *formater1=[[NSDateFormatter alloc]init]; formater1.dateFormat=@"yyyy-MM-dd"; person1.birthday=[formater1 dateFromString:@"1986-08-08"]; NSString *path1=@"/Users/kenshincui/Desktop/person1.arc"; [NSKeyedArchiver archiveRootObject:person1 toFile:path1]; Person *person2= [NSKeyedUnarchiver unarchiveObjectWithFile:path1]; NSLog(@"%@",person2); /*结果: name=Kenshin,age=28,height=0.00,birthday=1986-08-08 */ return 0; }