objective-c Foundation框架常用方法
Foundation框架中日期的操作
这里的方法来自己博客园中http://www.cnblogs.com/kenshincui/p/3885689.html
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { NSDate *date1=[NSDate date];//获得当前日期 NSLog(@"%@",date1); //结果:2014-07-16 07:25:28 +0000 NSDate *date2=[NSDate dateWithTimeIntervalSinceNow:100];//在当前日期的基础上加上100秒,注意在ObjC中多数时间单位都是秒 NSLog(@"%@",date2); //结果:2014-07-16 07:27:08 +0000 NSDate *date3=[NSDate distantFuture];//随机获取一个将来的日期 NSLog(@"%@",date3); //结果:4001-01-01 00:00:00 +0000 NSTimeInterval time=[date2 timeIntervalSinceDate:date1];//日期之差,返回单位为秒 NSLog(@"%f",time); //结果:100.008833 NSDate *date5=[date1 earlierDate:date3];//返回比较早的日期 NSLog(@"%@",date5); //结果:2014-07-16 07:25:28 +0000 //日期格式化 NSDateFormatter *formater1=[[NSDateFormatter alloc]init]; formater1.dateFormat=@"yy-MM-dd HH:mm:ss"; NSString *datestr1=[formater1 stringFromDate:date1]; NSLog(@"%@",datestr1); //结果:14-07-16 15:25:28 //字符串转化为日期 NSDate *date6=[formater1 dateFromString:@"14-02-14 11:07:16"]; NSLog(@"%@",date6); //结果:2014-02-14 03:07:16 +0000 return 0; }
字符串
在ObjC中字符串操作要比在C语言中简单的多,在下面的例子中你将看到字符串的初始化、大小写转化、后缀前缀判断、字符串比较、字符串截取、字符串转换等,通过下面的例子我们基本可以掌握常用的字符串操作(注意这些内容虽然基本,但却是十分常用的操作,需要牢记):
1 #import <Foundation/Foundation.h> 2 3 4 /**字符串操作*/ 5 void test1(){ 6 char *str1="C string";//这是C语言创建的字符串 7 NSString *str2=@"OC string";//ObjC字符串需要加@,并且这种方式创建的对象不需要自己释放内存 8 9 //下面的创建方法都应该释放内存 10 NSString *str3=[[NSString alloc] init]; 11 str3=@"OC string"; 12 NSString *str4=[[NSString alloc] initWithString:@"Objective-C string"]; 13 NSString *str5=[[NSString alloc] initWithFormat:@"age is %i,name is %.2f",19,1.72f]; 14 NSString *str6=[[NSString alloc] initWithUTF8String:"C string"];//C语言的字符串转换为ObjC字符串 15 16 //以上方法都有对应静态方法(一般以string开头),不需要管理内存(系统静态方法一般都是自动释放) 17 NSString *str7=[NSString stringWithString:@"Objective-C string"]; 18 } 19 void test2(){ 20 NSLog(@"\"Hello world!\" to upper is %@",[@"Hello world!" uppercaseString]); 21 //结果:"Hello world!" to upper is HELLO WORLD! 22 NSLog(@"\"Hello world!\" to lowwer is %@",[@"Hello world!" lowercaseString]); 23 //结果:"Hello world!" to lowwer is hello world! 24 25 //首字母大写,其他字母小写 26 NSLog(@"\"Hello world!\" to capitalize is %@",[@"Hello world!" capitalizedString]); 27 //结果:"Hello world!" to capitalize is Hello World! 28 29 BOOL result= [@"abc" isEqualToString:@"aBc"]; 30 NSLog(@"%i",result); 31 //结果:0 32 NSComparisonResult result2= [@"abc" compare:@"aBc"];//如果是[@"abc" caseInsensitiveCompare:@"aBc"]则忽略大小写比较 33 if(result2==NSOrderedAscending){ 34 NSLog(@"left<right."); 35 }else if(result2==NSOrderedDescending){ 36 NSLog(@"left>right."); 37 }else if(result2==NSOrderedSame){ 38 NSLog(@"left=right."); 39 } 40 //结果:left>right. 41 } 42 void test3(){ 43 NSLog(@"has prefix ab? %i",[@"abcdef" hasPrefix:@"ab"]); 44 //结果:has prefix ab? 1 45 NSLog(@"has suffix ab? %i",[@"abcdef" hasSuffix:@"ef"]); 46 //结果:has suffix ab? 1 47 NSRange range=[@"abcdefabcdef" rangeOfString:@"cde"];//注意如果遇到cde则不再往后面搜索,如果从后面搜索或其他搜索方式可以设置第二个options参数 48 if(range.location==NSNotFound){ 49 NSLog(@"not found."); 50 }else{ 51 NSLog(@"range is %@",NSStringFromRange(range)); 52 } 53 //结果:range is {2, 3} 54 } 55 //字符串分割 56 void test4(){ 57 NSLog(@"%@",[@"abcdef" substringFromIndex:3]);//从第三个索引开始(包括第三个索引对应的字符)截取到最后一位 58 //结果:def 59 NSLog(@"%@",[@"abcdef" substringToIndex:3]);////从0开始截取到第三个索引(不包括第三个索引对应的字符) 60 //结果:abc 61 NSLog(@"%@",[@"abcdef" substringWithRange:NSMakeRange(2, 3)]); 62 //结果:cde 63 NSString *str1=@"12.abcd.3a"; 64 NSArray *array1=[str1 componentsSeparatedByString:@"."];//字符串分割 65 NSLog(@"%@",array1); 66 /*结果: 67 ( 68 12, 69 abcd, 70 3a 71 ) 72 */ 73 74 } 75 //其他操作 76 void test5(){ 77 NSLog(@"%i",[@"12" intValue]);//类型转换 78 //结果:12 79 NSLog(@"%zi",[@"hello world,世界你好!" length]);//字符串长度注意不是字节数 80 //结果:17 81 NSLog(@"%c",[@"abc" characterAtIndex:0]);//取出制定位置的字符 82 //结果:a 83 const char *s=[@"abc" UTF8String];//转换为C语言字符串 84 NSLog(@"%s",s); 85 //结果:abc 86 } 87 88 int main(int argc, const char * argv[]) { 89 test1(); 90 test2(); 91 test3(); 92 test4(); 93 test5(); 94 return 0; 95 }
文件操作
1 #import <Foundation/Foundation.h> 2 3 4 void test1(){ 5 //读取文件内容 6 NSString *path=@"/Users/kenshincui/Desktop/test.txt"; 7 NSString *str1=[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; 8 //注意上面也可以使用gb2312 gbk等,例如kCFStringEncodingGB_18030_2000,但是需要用CFStringConvertEncodingToNSStringEncoding转换 9 NSLog(@"str1 is %@",str1); 10 //结果:str1 is hello world,世界你好! 11 12 13 14 15 //上面我们看到了读取文件,但并没有处理错误,当然在ObjC中可以@try @catch @finnally但通常我们并不那么做 16 //由于我们的test.txt中有中文,所以使用下面的编码读取会报错,下面的代码演示了错误获取的过程 17 NSError *error; 18 NSString *str2=[NSString stringWithContentsOfFile:path encoding:kCFStringEncodingGB_18030_2000 error:&error];//注意这句话中的error变量是**error,就是指针的指针那就是指针的地址,由于error就是一个指针此处也就是error的地址&error,具体原因见下面补充 19 if(error){ 20 NSLog(@"read error ,the error is %@",error); 21 }else{ 22 NSLog(@"read success,the file content is %@",str2); 23 } 24 //结果:read error ,the error is Error Domain=NSCocoaErrorDomain Code=261 "The file couldn’t be opened using the specified text encoding." UserInfo=0x100109620 {NSFilePath=/Users/kenshincui/Desktop/test.txt, NSStringEncoding=1586} 25 26 27 28 29 //读取文件内容还有一种方式就是利用URl,它除了可以读取本地文件还可以读取网络文件 30 //NSURL *url=[NSURL URLWithString:@"file:///Users/kenshincui/Desktop/test.txt"]; 31 NSURL *url=[NSURL URLWithString:@"http://www.apple.com"]; 32 NSString *str3=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; 33 NSLog(@"str3 is %@",str3); 34 } 35 void test2(){ 36 //下面是文件写入 37 NSString *path1=@"/Users/kenshincui/Desktop/test2.txt"; 38 NSError *error1; 39 NSString *str11=@"hello world,世界你好!"; 40 [str11 writeToFile:path1 atomically:YES encoding:NSUTF8StringEncoding error:&error1];//automically代表一次性写入,如果写到中间出错了最后就全部不写入 41 if(error1){ 42 NSLog(@"write fail,the error is %@",[error1 localizedDescription]);//调用localizedDescription是只打印关键错误信息 43 }else{ 44 NSLog(@"write success!"); 45 } 46 //结果:write success! 47 } 48 //路径操作 49 void test3(){ 50 NSMutableArray *marray=[NSMutableArray array];//可变数组 51 [marray addObject:@"Users"]; 52 [marray addObject:@"KenshinCui"]; 53 [marray addObject:@"Desktop"]; 54 55 NSString *path=[NSString pathWithComponents:marray]; 56 NSLog(@"%@",path);//字符串拼接成路径 57 //结果:Users/KenshinCui/Desktop 58 59 NSLog(@"%@",[path pathComponents]);//路径分割成数组 60 /*结果: 61 ( 62 Users, 63 KenshinCui, 64 Desktop 65 ) 66 */ 67 68 NSLog(@"%i",[path isAbsolutePath]);//是否绝对路径(其实就是看字符串是否以“/”开头) 69 //结果:0 70 NSLog(@"%@",[path lastPathComponent]);//取得最后一个目录 71 //结果:Desktop 72 NSLog(@"%@",[path stringByDeletingLastPathComponent]);//删除最后一个目录,注意path本身是常量不会被修改,只是返回一个新字符串 73 //结果:Users/KenshinCui 74 NSLog(@"%@",[path stringByAppendingPathComponent:@"Documents"]);//路径拼接 75 //结果:Users/KenshinCui/Desktop/Documents 76 } 77 //扩展名操作 78 void test4(){ 79 NSString *path=@"Users/KenshinCui/Desktop/test.txt"; 80 NSLog(@"%@",[path pathExtension]);//取得扩展名,注意ObjC中扩展名不包括"." 81 //结果:txt 82 NSLog(@"%@",[path stringByDeletingPathExtension]);//删除扩展名,注意包含"." 83 //结果:Users/KenshinCui/Desktop/test 84 NSLog(@"%@",[@"Users/KenshinCui/Desktop/test" stringByAppendingPathExtension:@"mp3"]);//添加扩展名 85 //结果:Users/KenshinCui/Desktop/test.mp3 86 } 87 88 int main(int argc, const char * argv[]) { 89 test1(); 90 test2(); 91 test3(); 92 test4(); 93 return 0; 94 }
可变字符串
我们知道在字符串操作过程中我们经常希望改变原来的字符串,当然这在C语言中实现比较复杂,但是ObjC为我们提供了新的可变字符串类NSMutableString,它是NSString的子类。
1 #import <Foundation/Foundation.h> 2 3 4 int main(int argc, const char * argv[]) { 5 6 /*可变字符串,注意NSMutableString是NSString子类*/ 7 //注意虽然initWithCapacity分配字符串大小,但是不是绝对的不可以超过此范围,声明此变量对性能有好处 8 NSMutableString *str1= [[NSMutableString alloc] initWithCapacity:10]; 9 [str1 setString:@"hello"];//设置字符串 10 NSLog(@"%@",str1); 11 //结果:hello 12 13 [str1 appendString:@",world!"];//追加字符串 14 NSLog(@"%@",str1); 15 //结果:hello,world! 16 17 [str1 appendFormat:@"我的年龄是%i。dear,I love you.",18]; 18 NSLog(@"%@",str1); 19 //结果:hello,world!我的年龄是18。dear,I love you. 20 21 //替换字符串 22 NSRange range=[str1 rangeOfString:@"dear"]; 23 [str1 replaceCharactersInRange:range withString:@"Honey"]; 24 NSLog(@"%@",str1); 25 //结果:hello,world!我的年龄是18。Honey,I love you. 26 27 //插入字符串 28 [str1 insertString:@"My name is Kenshin." atIndex:12]; 29 NSLog(@"%@",str1); 30 //结果:hello,world!My name is Kenshin.我的年龄是18。Honey,I love you. 31 32 //删除指定字符串 33 [str1 deleteCharactersInRange:[str1 rangeOfString:@"My name is Kenshin."]];//删除指定范围的字符串 34 NSLog(@"%@",str1); 35 //结果:hello,world!我的年龄是18。Honey,I love you. 36 37 return 0; 38 }
不可变数组
需要注意几点:
- NSArray中只能存放对象,不能存放基本数据类型,通常我们可以通过在基本数据类型前加@进行转换;
- 数组中的元素后面必须加nil以表示数据结束;
- makeObjectsPerformSelector执行数组中对象的方法,其参数最多只能有一个;
- 上面数组操作中无论是数组的追加、删除、截取都没有改变原来的数组,只是产生了新的数组而已;
- 对象的比较除了使用系统自带的方法,我们可以通过自定义比较器的方法来实现;
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 4 5 void test1(){ 6 //NSArray长度不可变所以初始化的时候就赋值,并且最后以nil结尾 7 //此外需要注意NSArray不能存放C语言的基础类型 8 NSObject *obj=[[NSObject alloc]init]; 9 //NSArray *array1=[[NSArray alloc] initWithObjects:@"abc",obj,@"cde",@"opq", nil]; 10 NSArray *array1=[NSArray arrayWithObjects:@"abc",obj,@"cde",@"opq",@25, nil]; 11 NSLog(@"%zi",array1.count);//数组长度,结果:5 12 NSLog(@"%i",[array1 containsObject:@"cde"]);//是否包含某个对象,结果:1 13 NSLog(@"%@",[array1 lastObject]);//最后一个对象,结果:25 14 NSLog(@"%zi",[array1 indexOfObject:@"abc"]);//对象所在的位置:0 15 16 Person *person1=[Person personWithName:@"Kenshin"]; 17 Person *person2=[Person personWithName:@"Kaoru"]; 18 Person *person3=[Person personWithName:@"Rosa"]; 19 NSArray *array2=[[NSArray alloc]initWithObjects:person1,person2,person3, nil]; 20 [array2 makeObjectsPerformSelector:@selector(showMessage:) withObject:@"Hello,world!"];//执行所有元素的showMessage方法,后面的参数最多只能有一个 21 /*结果: 22 My name is Kenshin,the infomation is "Hello,world!". 23 My name is Kaoru,the infomation is "Hello,world!". 24 My name is Rosa,the infomation is "Hello,world!". 25 */ 26 } 27 //数组的遍历 28 void test2(){ 29 NSObject *obj=[[NSObject alloc]init]; 30 NSArray *array=[[NSArray alloc] initWithObjects:@"abc",obj,@"cde",@"opq",@25, nil]; 31 //方法1 32 for(int i=0,len=array.count;i<len;++i){ 33 NSLog(@"method1:index %i is %@",i,[array objectAtIndex:i]); 34 } 35 /*结果: 36 method1:index 0 is abc 37 method1:index 1 is <NSObject: 0x100106de0> 38 method1:index 2 is cde 39 method1:index 3 is opq 40 method1:index 4 is 25 41 */ 42 43 44 //方法2 45 for(id obj in array){ 46 NSLog(@"method2:index %zi is %@",[array indexOfObject:obj],obj); 47 } 48 /*结果: 49 method2:index 0 is abc 50 method2:index 1 is <NSObject: 0x100602f00> 51 method2:index 2 is cde 52 method2:index 3 is opq 53 method2:index 4 is 25 54 */ 55 56 57 //方法3,利用代码块方法 58 [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 59 NSLog(@"method3:index %zi is %@",idx,obj); 60 if(idx==2){//当idx=2时设置*stop为YES停止遍历 61 *stop=YES; 62 } 63 }]; 64 /*结果: 65 method3:index 0 is abc 66 method3:index 1 is <NSObject: 0x100106de0> 67 method3:index 2 is cde 68 */ 69 70 71 //方法4,利用迭代器 72 //NSEnumerator *enumerator= [array objectEnumerator];//获得一个迭代器 73 NSEnumerator *enumerator=[array reverseObjectEnumerator];//获取一个反向迭代器 74 //NSLog(@"all:%@",[enumerator allObjects]);//获取所有迭代对象,注意调用完此方法迭代器就遍历完了,下面的nextObject就没有值了 75 id obj2=nil; 76 while (obj2=[enumerator nextObject]) { 77 NSLog(@"method4:%@",obj2); 78 } 79 /*结果: 80 method4:25 81 method4:opq 82 method4:cde 83 method4:<NSObject: 0x100106de0> 84 method4:abc 85 */ 86 } 87 //数组派生出新的数组 88 void test3(){ 89 NSArray *array=[NSArray arrayWithObjects:@"1",@"2",@"3", nil]; 90 NSArray *array2=[array arrayByAddingObject:@"4"];//注意此时array并没有变 91 NSLog(@"%@",array2); 92 /*结果: 93 ( 94 1, 95 2, 96 3, 97 4 98 ) 99 */ 100 101 102 NSLog(@"%@",[array2 arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:@"5",@"6", nil]]);//追加形成新的数组 103 /*结果: 104 ( 105 1, 106 2, 107 3, 108 4, 109 5, 110 6 111 ) 112 */ 113 114 115 NSLog(@"%@",[array2 subarrayWithRange:NSMakeRange(1, 3)]);//根据一定范围取得生成一个新的数组 116 /*结果: 117 ( 118 2, 119 3, 120 4 121 ) 122 */ 123 124 125 NSLog(@"%@",[array componentsJoinedByString:@","]);//数组连接,形成一个字符串 126 //结果:1,2,3 127 128 //读写文件 129 NSString *path=@"/Users/KenshinCui/Desktop/array.xml"; 130 [array writeToFile:path atomically:YES]; 131 NSArray *array3=[NSArray arrayWithContentsOfFile:path]; 132 NSLog(@"%@",array3); 133 /*结果: 134 ( 135 1, 136 2, 137 3 138 ) 139 */ 140 } 141 //数组排序 142 void test4(){ 143 //方法1,使用自带的比较器 144 NSArray *array=[NSArray arrayWithObjects:@"3",@"1",@"2", nil]; 145 NSArray *array2= [array sortedArrayUsingSelector:@selector(compare:)]; 146 NSLog(@"%@",array2); 147 /*结果: 148 ( 149 1, 150 2, 151 3 152 ) 153 */ 154 155 156 //方法2,自己定义比较器 157 Person *person1=[Person personWithName:@"Kenshin"]; 158 Person *person2=[Person personWithName:@"Kaoru"]; 159 Person *person3=[Person personWithName:@"Rosa"]; 160 NSArray *array3=[NSArray arrayWithObjects:person1,person2,person3, nil]; 161 NSArray *array4=[array3 sortedArrayUsingSelector:@selector(comparePerson:)]; 162 NSLog(@"%@",array4); 163 /*结果: 164 ( 165 "name=Kaoru", 166 "name=Kenshin", 167 "name=Rosa" 168 ) 169 */ 170 171 172 //方法3使用代码块 173 NSArray *array5=[array3 sortedArrayUsingComparator:^NSComparisonResult(Person *obj1, Person *obj2) { 174 return [obj2.name compare:obj1.name];//降序 175 }]; 176 NSLog(@"%@",array5); 177 /*结果: 178 ( 179 "name=Rosa", 180 "name=Kenshin", 181 "name=Kaoru" 182 ) 183 */ 184 185 186 //方法4 通过描述器定义排序规则 187 Person *person4=[Person personWithName:@"Jack"]; 188 Person *person5=[Person personWithName:@"Jerry"]; 189 Person *person6=[Person personWithName:@"Tom"]; 190 Person *person7=[Person personWithName:@"Terry"]; 191 NSArray *array6=[NSArray arrayWithObjects:person4,person5,person6,person7, nil]; 192 //定义一个排序描述 193 NSSortDescriptor *personName=[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; 194 NSSortDescriptor *accountBalance=[NSSortDescriptor sortDescriptorWithKey:@"account.balance" ascending:YES]; 195 NSArray *des=[NSArray arrayWithObjects:personName,accountBalance, nil];//先按照person的name排序再按照account的balance排序 196 NSArray *array7=[array6 sortedArrayUsingDescriptors:des]; 197 NSLog(@"%@",array7); 198 /*结果: 199 ( 200 "name=Jack", 201 "name=Jerry", 202 "name=Terry", 203 "name=Tom" 204 ) 205 */ 206 } 207 208 int main(int argc, const char * argv[]) { 209 test1(); 210 test2(); 211 test3(); 212 test4(); 213 return 0; 214 }
可变数组
- 可变数组中的元素后面必须加nil以表示数据结束;
- 往一个可变数组中添加一个对象,此时这个对象的引用计数器会加1,当这个对象从可变数组中移除其引用计数器减1。同时当整个数组销毁之后会依次调用每个对象的releaes方法。
- 在不可变数组中无论对数组怎么排序,原来的数组顺序都不会改变,但是在可变数组中如果使用sortUsingSelector:排序原来的数组顺序就发生了变化。
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 4 5 void test1(){ 6 Person *person1=[Person personWithName:@"Kenshin"]; 7 Person *person2=[Person personWithName:@"Kaoru"]; 8 Person *person3=[Person personWithName:@"Rosa"]; 9 NSMutableArray *array1=[NSMutableArray arrayWithObjects:person1,person2,person3, nil]; 10 NSLog(@"%@",array1); 11 /*结果: 12 ( 13 "name=Kenshin", 14 "name=Kaoru", 15 "name=Rosa" 16 ) 17 */ 18 19 Person *person4=[Person personWithName:@"Jack"];//此时person4的retainCount为1 20 [array1 addObject:person4];//添加一个元素,此时person4的retainCount为2 21 NSLog(@"%@",array1); 22 /*结果: 23 ( 24 "name=Kenshin", 25 "name=Kaoru", 26 "name=Rosa", 27 "name=Jack" 28 ) 29 */ 30 31 [array1 removeObject:person3];//删除一个元素 32 NSLog(@"%@",array1); 33 /*结果: 34 ( 35 "name=Kenshin", 36 "name=Kaoru", 37 "name=Jack" 38 ) 39 */ 40 41 [array1 removeLastObject];//删除最后一个元素,//此时person4的retainCount为1 42 NSLog(@"%@",array1); 43 /*结果: 44 ( 45 "name=Kenshin", 46 "name=Kaoru" 47 ) 48 */ 49 50 [array1 removeAllObjects];//删除所以元素 51 52 //注意当往数组中添加一个元素时会retain因此计数器+1,当从数组中移除一个元素时会release因此计数器-1 53 //当NSMutalbeArray对象release的时候会依次调用每一个对象的release 54 } 55 void test2(){ 56 NSMutableArray *array1=[NSMutableArray arrayWithObjects:@"1",@"3",@"2", nil]; 57 NSLog(@"%@",array1); 58 /*结果: 59 ( 60 1, 61 3, 62 2 63 ) 64 */ 65 66 NSArray *array2= [array1 sortedArrayUsingSelector:@selector(compare:)];//注意这个方法没有修改array1 67 NSLog(@"%@",array1); 68 /*结果: 69 ( 70 1, 71 3, 72 2 73 ) 74 */ 75 76 NSLog(@"%@",array2); 77 /*结果: 78 ( 79 1, 80 2, 81 3 82 ) 83 */ 84 [array1 sortUsingSelector:@selector(compare:)];//这个方法会修改array1 85 NSLog(@"%@",array1); 86 /*结果: 87 ( 88 1, 89 2, 90 3 91 ) 92 */ 93 94 } 95 96 int main(int argc, const char * argv[]) { 97 98 test1(); 99 100 test2(); 101 102 return 0; 103 }
字典
1 #import <Foundation/Foundation.h> 2 3 4 void test1(){ 5 NSDictionary *dic1=[NSDictionary dictionaryWithObject:@"1" forKey:@"a"]; 6 NSLog(@"%@",dic1); 7 /*结果: 8 { 9 a = 1; 10 } 11 */ 12 13 //常用的方式 14 NSDictionary *dic2=[NSDictionary dictionaryWithObjectsAndKeys: 15 @"1",@"a", 16 @"2",@"b", 17 @"3",@"c", 18 nil]; 19 NSLog(@"%@",dic2); 20 /*结果: 21 { 22 a = 1; 23 b = 2; 24 c = 3; 25 } 26 */ 27 28 29 NSDictionary *dic3=[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1",@"2", nil] forKeys:[NSArray arrayWithObjects:@"a",@"b", nil]]; 30 NSLog(@"%@",dic3); 31 /*结果: 32 { 33 a = 1; 34 b = 2; 35 } 36 */ 37 38 39 //更简单的方式 40 NSDictionary *dic4=@{@"1":@"a",@"2":@"b",@"3":@"c"}; 41 NSLog(@"%@",dic4); 42 /*结果: 43 { 44 1 = a; 45 2 = b; 46 3 = c; 47 } 48 */ 49 } 50 void test2(){ 51 NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys: 52 @"1",@"a", 53 @"2",@"b", 54 @"3",@"c", 55 @"2",@"d", 56 nil]; 57 NSLog(@"%zi",[dic1 count]); //结果:4 58 NSLog(@"%@",[dic1 valueForKey:@"b"]);//根据键取得值,结果:2 59 NSLog(@"%@",dic1[@"b"]);//还可以这样读取,结果:2 60 NSLog(@"%@,%@",[dic1 allKeys],[dic1 allValues]); 61 /*结果: 62 ( 63 d, 64 b, 65 c, 66 a 67 ),( 68 2, 69 2, 70 3, 71 1 72 ) 73 74 */ 75 76 NSLog(@"%@",[dic1 objectsForKeys:[NSArray arrayWithObjects:@"a",@"e" , nil]notFoundMarker:@"not fount"]);//后面一个参数notFoundMarker是如果找不到对应的key用什么值代替 77 /*结果: 78 ( 79 1, 80 "not fount" 81 ) 82 */ 83 } 84 void test3(){ 85 NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys: 86 @"1",@"a", 87 @"2",@"b", 88 @"3",@"c", 89 @"2",@"d", 90 nil]; 91 //遍历1 92 for (id key in dic1) {//注意对于字典for遍历循环的是key 93 NSLog(@"%@=%@",key,[dic1 objectForKey:key]); 94 } 95 /*结果: 96 d=2 97 b=2 98 c=3 99 a=1 100 */ 101 102 //遍历2 103 NSEnumerator *enumerator=[dic1 keyEnumerator];//还有值的迭代器[dic1 objectEnumerator] 104 id key=nil; 105 while (key=[enumerator nextObject]) { 106 NSLog(@"%@=%@",key,[dic1 objectForKey:key]); 107 108 } 109 /*结果: 110 d=2 111 b=2 112 c=3 113 a=1 114 */ 115 116 //遍历3 117 [dic1 enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 118 NSLog(@"%@=%@",key,obj); 119 }]; 120 /*结果: 121 d=2 122 b=2 123 c=3 124 a=1 125 */ 126 } 127 128 void test4(){ 129 NSMutableDictionary *dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:@"1",@"a", 130 @"2",@"b", 131 @"3",@"c", 132 @"2",@"d", 133 nil]; 134 [dic removeObjectForKey:@"b"]; 135 NSLog(@"%@",dic); 136 /*结果: 137 { 138 a = 1; 139 c = 3; 140 d = 2; 141 } 142 */ 143 144 [dic addEntriesFromDictionary:@{@"e":@"7",@"f":@"6"}]; 145 NSLog(@"%@",dic); 146 /*结果: 147 { 148 a = 1; 149 c = 3; 150 d = 2; 151 e = 7; 152 f = 6; 153 } 154 */ 155 156 [dic setValue:@"5" forKey:@"a"]; 157 NSLog(@"%@",dic); 158 /*结果: 159 { 160 a = 5; 161 c = 3; 162 d = 2; 163 e = 7; 164 f = 6; 165 } 166 */ 167 168 169 //注意,一个字典的key或value添加到字典中时计数器+1;字典释放时调用key或value的release一次,计数器-1 170 } 171 172 173 int main(int argc, const char * argv[]) { 174 test1(); 175 test2(); 176 test3(); 177 test4(); 178 return 0; 179 }
装箱和拆箱
其实从上面的例子中我们也可以看到,数组和字典中只能存储对象类型,其他基本类型和结构体是没有办法放到数组和字典中的,当然你也是无法给它们发送消息的(也就是说有些NSObject的方法是无法调用的),这个时候通常会用到装箱(boxing)和拆箱(unboxing)。其实各种高级语言基本上都有装箱和拆箱的过程,例如C#中我们将基本数据类型转化为Object就是一个装箱的过程,将这个Object对象转换为基本数据类型的过程就是拆箱,而且在C#中装箱的过程可以自动完成,基本数据类型可以直接赋值给Object对象。但是在ObjC中装箱的过程必须手动实现,ObjC不支持自动装箱。
在ObjC中我们一般将基本数据类型装箱成NSNumber类型(当然它也是NSObject的子类,但是NSNumber不能对结构体装箱),调用其对应的方法进行转换:
+(NSNumber *)numberWithChar:(char)value;
+(NSNumber *)numberWithInt:(int)value;
+(NSNumber *)numberWithFloat:(float)value;
+(NSNumber *)numberWithDouble:(double)value;
+(NSNumber *)numberWithBool:(BOOL)value;
+(NSNumber *)numberWithInteger:(NSInteger)value;
拆箱的过程就更加简单了,可以调用如下方法:
-(char)charValue;
-(int)intValue;
-(float)floatValue;
-(double)doubleValue;
-(BOOL)boolValue;
1 #import <Foundation/Foundation.h> 2 3 4 /*可以存放基本类型到数组、字典*/ 5 void test1(){ 6 //包装类NSNumber,可以包装基本类型但是无法包装结构体类型 7 NSNumber *number1=[NSNumber numberWithChar:'a'];//'a'是一个C语言的char类型我们无法放倒NSArray中,但是我们可以通过NSNumber包装 8 NSArray *array1=[NSArray arrayWithObject:number1]; 9 NSLog(@"%@",array1); 10 /*结果: 11 ( 12 97 13 ) 14 */ 15 16 NSNumber *number2= [array1 lastObject]; 17 NSLog(@"%@",number2);//返回的不是基本类型,结果:97 18 19 20 char char1=[number2 charValue];//number转化为char 21 NSLog(@"%c",char1); //结果:a 22 } 23 24 int main(int argc, const char * argv[]) { 25 test1(); 26 return 0; 27 }
那么如果是我们自定义的结构体类型呢,这个时候我们需要使用NSValue如下方法进行装箱:
+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
调用下面的方法进行拆箱:
-(void)getValue:(void *)value;
1 #import <Foundation/Foundation.h> 2 3 typedef struct { 4 int year; 5 int month; 6 int day; 7 } Date; 8 9 10 //NSNumber是NSValue的子类,而NSValue可以包装任何类型,包括结构体 11 void test1(){ 12 //如果我们自己定义的结构体包装 13 Date date={2014,2,28}; 14 char *type=@encode(Date); 15 NSValue *value3=[NSValue value:&date withObjCType:type];//第一参数传递结构体地址,第二个参数传递类型字符串 16 NSArray *array2=[NSArray arrayWithObject:value3]; 17 NSLog(@"%@",array2); 18 /*结果: 19 ( 20 "<de070000 02000000 1c000000>" 21 ) 22 */ 23 24 Date date2; 25 [value3 getValue:&date2];//取出对应的结构体,注意没有返回值 26 //[value3 objCType]//取出包装内容的类型 27 NSLog(@"%i,%i,%i",date2.year,date2.month,date2.day); //结果:2014,2,28 28 29 } 30 31 32 int main(int argc, const char * argv[]) { 33 test1(); 34 return 0; 35 }
扩展1-NSNull
通过前面的介绍大家都知道无论在数组还是在字典中都必须以nil结尾,否则数组或字典无法判断是否这个数组或字典已经结束(与C语言中的字符串比较类似,C语言中定义字符串后面必须加一个”\0”)。但是我们有时候确实想在数据或字典中存储nil值而不是作为结束标记怎么办呢?这个时候需要使用NSNull,这个类是一个单例,只有一个null方法。简单看一下:
1 #import <Foundation/Foundation.h> 2 3 4 5 int main(int argc, const char * argv[]) { 6 7 NSNull *nl=[NSNull null];//注意这是一个对象,是一个单例,只有一个方法null创建一个对象 8 NSNull *nl2=[NSNull null]; 9 NSLog(@"%i",nl==nl2);//由于是单例所以地址相等,结果:1 10 11 NSArray *array1=[NSArray arrayWithObjects:@"abc",nl,@123, nil]; 12 NSLog(@"%@",array1); 13 /*结果: 14 ( 15 abc, 16 "<null>", 17 123 18 ) 19 */ 20 21 return 0; 22 }
扩展2-@符号
我们知道在ObjC中很多关键字前都必须加上@符号,例如@protocol、@property等,当然ObjC中的字符串必须使用@符号,还有就是%@可以表示输出一个对象。其实@符号在新版的ObjC中还有一个作用:装箱。
相信聪明的童鞋在前面的例子中已经看到了,这里简单的介绍一下(在下面的演示中你也将看到很多ObjC新特性)。
1 #import <Foundation/Foundation.h> 2 3 typedef enum { 4 spring, 5 summer, 6 autumn, 7 winter 8 } Season; 9 10 int main(int argc, const char * argv[]) { 11 /*装箱*/ 12 NSNumber *number1=@100; 13 NSArray *array1=[NSArray arrayWithObjects:number1,@"abc",@16,@'A',@16.7,@YES, nil]; 14 NSLog(@"%@",array1); 15 /*结果: 16 ( 17 100, 18 abc, 19 16, 20 65, 21 "16.7" 22 1 23 ) 24 */ 25 NSNumber *number2=@(1+2*3); 26 NSLog(@"%@",number2); //结果:7 27 NSNumber *number3=@(autumn); 28 NSLog(@"%@",number3); //结果:2 29 30 31 NSArray *array2=@[@"abc",@16,@'A',@16.7,@YES];//使用这种方式最后不用添加nil值了 32 NSLog(@"%@",array2[2]); //结果:65 33 NSMutableArray *array3=[NSMutableArray arrayWithArray:array2]; 34 array3[0]=@"def"; 35 NSLog(@"%@",array3[0]); //结果:def 36 37 NSDictionary *dic1=@{@"a":@123,@"b":@'c',@"c":@YES}; 38 NSLog(@"%@",dic1); 39 /*结果: 40 { 41 a = 123; 42 b = 99; 43 c = 1; 44 } 45 */ 46 NSMutableDictionary *dic2=[NSMutableDictionary dictionaryWithDictionary:dic1]; 47 dic2[@"a"]=@456; 48 NSLog(@"%@",dic2[@"a"]);//结果:456 49 50 return 0; 51 }
反射
由于ObjC动态性,在ObjC中实现反射可以说是相当简单,下面代码中演示了常用的反射操作,具体作用也都在代码中进行了注释说明:
1 #import <Foundation/Foundation.h> 2 3 @interface Account : NSObject 4 5 @property (nonatomic,assign) double balance; 6 7 @end
1 #import "Account.h" 2 3 @implementation Account 4 5 @end
1 #import <Foundation/Foundation.h> 2 @class Account; 3 4 @interface Person : NSObject 5 6 @property (nonatomic,copy) NSString *name; 7 @property (nonatomic,retain) Account *account; 8 9 -(Person *)initWithName:(NSString *)name; 10 11 +(Person *)personWithName:(NSString *)name; 12 13 -(void)showMessage:(NSString *)infomation; 14 15 //自己实现对象比较方法 16 -(NSComparisonResult)comparePerson:(Person *)person; 17 @end
1 #import "Person.h" 2 3 @implementation Person 4 5 -(Person *)initWithName:(NSString *)name{ 6 if(self=[super init]){ 7 self.name=name; 8 } 9 return self; 10 } 11 12 +(Person *)personWithName:(NSString *)name{ 13 Person *person=[[Person alloc]initWithName:name]; 14 return person; 15 } 16 17 -(void)showMessage:(NSString *)infomation{ 18 NSLog(@"My name is %@,the infomation is \"%@\".",_name,infomation); 19 } 20 21 //自己实现对象比较方法 22 -(NSComparisonResult)comparePerson:(Person *)person{ 23 return [_name compare:person.name]; 24 } 25 26 -(NSString *)description{ 27 return [NSString stringWithFormat:@"name=%@",_name]; 28 } 29 30 @end
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 4 5 int main(int argc, const char * argv[]) { 6 /*常用方法*/ 7 Person *person1=[Person personWithName:@"Kenshin"]; 8 NSLog(@"%i",[person1 isKindOfClass:[NSObject class]]); //判断一个对象是否为某种类型(如果是父类也返回YES),结果:1 9 NSLog(@"%i",[person1 isMemberOfClass:[NSObject class]]); //判断一个对象是否是某个类的实例化对象,结果:0 10 NSLog(@"%i",[person1 isMemberOfClass:[Person class]]); //结果:1 11 NSLog(@"%i",[person1 conformsToProtocol:@protocol(NSCopying)]);//是否实现了某个协议,结果:0 12 NSLog(@"%i",[person1 respondsToSelector:@selector(showMessage:)]);//是否存在某个方法,结果:1 13 14 [person1 showMessage:@"Hello,world!"];//直接调用一个方法 15 [person1 performSelector:@selector(showMessage:) withObject:@"Hello,world!"]; 16 //动态调用一个方法,注意如果有参数那么参数类型只能为ObjC对象,并且最多只能有两个参数 17 18 19 /*反射*/ 20 //动态生成一个类 21 NSString *className=@"Person"; 22 Class myClass=NSClassFromString(className);//根据类名生成类 23 Person *person2=[[myClass alloc]init]; //实例化 24 person2.name=@"Kaoru"; 25 NSLog(@"%@",person2);//结果:name=Kaoru 26 27 //类转化为字符串 28 NSLog(@"%@,%@",NSStringFromClass(myClass),NSStringFromClass([Person class])); //结果:Person,Person 29 30 //调用方法 31 NSString *methodName=@"showMessage:"; 32 SEL mySelector=NSSelectorFromString(methodName); 33 Person *person3=[[myClass alloc]init]; 34 person3.name=@"Rosa"; 35 [person3 performSelector:mySelector withObject:@"Hello,world!"]; //结果:My name is Rosa,the infomation is "Hello,world!". 36 37 //方法转化为字符串 38 NSLog(@"%@",NSStringFromSelector(mySelector)); //结果:showMessage: 39 40 return 0; 41 }
拷贝
对象拷贝操作也比较常见,在ObjC中有两种方式的拷贝:copy和mutablecopy,这两中方式都将产生一个新的对象,只是后者产生的是一个可变对象。在ObjC中如果要想实现copy或者mutablecopy操作需要实现NSCopy或者NSMutableCopy协议,拷贝操作产生的新的对象默认引用计数器是1,在非ARC模式下我们应该对这个对象进行内存管理。在熟悉这两种操作之前我们首先需要弄清两个概念:深复制(或深拷贝)和浅复制(或浅拷贝)。
- 浅复制:在执行复制操作时,对于对象中每一层(对象中包含的对象,例如说属性是某个对象类型)复制都是指针复制(如果从引用计数器角度出发,那么每层对象的引用计数器都会加1)。
- 深复制:在执行复制操作时,至少有一个对象的复制是对象内容复制(如果从引用计数器角度出发,那么除了对象内容复制的那个对象的引用计数器不变,其他指针复制的对象其引用计数器都会加1)。
注:
指针拷贝:拷贝的是指针本身(也就是具体对象的地址)而不是指向的对象内容本身。
对象复制:对象复制指的是复制内容是对象本身而不是对象的地址。
完全复制:上面说了深复制和浅复制,既然深复制是至少一个对象复制是对象内容复制,那么如果所有复制都是对象内容复制那么这个复制就叫完全复制。
对比copy和mutablecopy其实前面我们一直还用到一个操作是retain,它们之间的关系如下:
retain:始终采取浅复制,引用计数器会加1,返回的对象和被复制对象是同一个对象1(也就是说这个对象的引用多了一个,或者说是指向这个对象的指针多了一个);
copy:对于不可变对象copy采用的是浅复制,引用计数器加1(其实这是编译器进行了优化,既然原来的对象不可变,复制之后的对象也不可变那么就没有必要再重新创建一个对象了);对于可变对象copy采用的是深复制,引用计数器不变(原来的对象是可变,现在要产生一个不可变的当然得重新产生一个对象);
mutablecopy:无论是可变对象还是不可变对象采取的都是深复制,引用计数器不变(如果从一个不可变对象产生一个可变对象自然不用说两个对象绝对不一样肯定是深复制;如果从一个可变对象产生出另一个可变对象,那么当其中一个对象改变自然不希望另一个对象改变,当然也是深复制)。
注:
可变对象:当值发生了改变,那么地址也随之发生改变;
不可变对象:当值发生了改变,内容首地址不发生变化;
引用计数器:用于计算一个对象有几个指针在引用(有几个指针变量指向同一个内存地址)
View Code1 #import <Foundation/Foundation.h> 2 3 4 void test1(){ 5 NSString *name=@"Kenshin"; 6 NSString *str1=[NSString stringWithFormat:@"I'm %@.",name];//注意此时str1的计数器是1 7 NSLog(@"%lu",[str1 retainCount]); //结果:1 8 9 10 NSMutableString *str2=[str1 mutableCopy];//注意此时str2的计数器为1,str1的计数器还是1 11 //NSMutableString *str5 =CFRetain((__bridge CFTypeRef)str2); 12 NSLog(@"retainCount(str1)=%lu,retainCount(str2)=%lu",[str1 retainCount],[str2 retainCount]); 13 //结果:retainCount(str1)=1,retainCount(str2)=1 14 15 16 [str2 appendString:@"def"];//改变str2,str1不变 17 NSLog(@"%zi",str1==str2);//二者不是向同一个对象,结果:0 18 NSLog(@"str1=%@",str1); //结果:str1=I'm Kenshin. 19 NSLog(@"str2=%@",str2); //结果:str2=I'm Kenshin.def 20 21 22 NSLog(@"str1's %lu",[str1 retainCount]); 23 NSString *str3=[str1 copy];//str3不是产生的新对象而是复制了对象指针,但是str1的计数器+1(当然既然str3同样指向同一个对象,那么如果计算str3指向的对象引用计数器肯定等于str1的对象引用计数器) 24 NSLog(@"%zi",str1==str3);//二者相等指向同一个对象,结果:1 25 NSLog(@"retainCount(str1)=%lu,retainCount(str3)=%lu",str1.retainCount,str3.retainCount); 26 //结果:retainCount(str1)=2,retainCount(str3)=2 27 28 //需要注意的是使用copy和mutableCopy是深复制还是浅复制不是绝对,关键看由什么对象产生什么样的对象 29 NSString *str4=[str2 copy];//由NSMutableString产生了NSString,二者类型都不同肯定是深拷贝,此时str2的计数器还是1,str4的计数器也是1 30 [str2 appendString:@"g"];//改变原对象不影响str4 31 NSLog(@"%zi",str2==str4); //结果:0 32 NSLog(@"str2=%@",str2); //结果:str2=I'm Kenshin.defg 33 NSLog(@"str4=%@",str4); //结果:str4=I'm Kenshin.def 34 35 36 [str1 release]; 37 str1=nil; 38 [str3 release];//其实这里也可以调用str1再次release,因为他们两个指向的是同一个对象(但是一般不建议那么做,不容易理解) 39 str3=nil; 40 41 [str2 release]; 42 str2=nil; 43 [str4 release]; 44 str4=nil; 45 46 //上面只有一种情况是浅拷贝:不可变对象调用copy方法 47 48 } 49 50 int main(int argc,char *argv[]){ 51 test1(); 52 return 0; 53 }