概述
我们前面的章节中就一直新建Cocoa Class,那么Cocoa到底是什么,它和我们前面以及后面要讲的内容到底有什么关系呢?Objective-C开发中经常用到NSObject,那么这个对象到底是谁?它为什么又出现在Objective-C中间呢?今天我们将揭开这层面纱,重点分析在IOS开发中一个重要的框架Foundation,今天的主要内容有:
Foundation概述
为什么前面说的内容中新建一个类的时候我们都是选择Cocoa Class呢?Cocoa是什么呢?
Cocoa不是一种编程语言(它可以运行多种编程语言),它也不是一个开发工具(通过命令行我们仍然可以开发Cocoa程序),它是创建Mac OS X和IOS程序的原生面向对象API,为这两者应用提供了编程环境。
我们通常称为“Cocoa框架”,事实上Cocoa本身是一个框架的集合,它包含了众多子框架,其中最重要的要数“Foundation”和“UIKit”。前者是框架的基础,和界面无关,其中包含了大量常用的API;后者是基础的UI类库,以后我们在IOS开发中会经常用到。这两个框架在系统中的位置如下图:
其实所有的Mac OS X和IOS程序都是由大量的对象构成,而这些对象的根对象都是NSObject,NSObject就处在Foundation框架之中,具体的类结构如下:
通常我们会将他们分为几类:
- 值对象
- 集合
- 操作系统服务:文件系统、URL、进程通讯
- 通知
- 归档和序列化
- 表达式和条件判断
- Objective-C语言服务
UIKit主要用于界面构架,这里我们不妨也看一下它的类结构:
常用结构体
在Foundation中定义了很多常用结构体类型来简化我们的日常开发,这些结构体完全采用Objective-C定义,和我们自己定义的结构体没有任何区别,之所以由框架为我们提供完全是为了简化我们的开发。常用的结构体有NSRange、NSPoint、NSSize、NSRect等
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> /*NSRange表示一个范围*/ void test1(){ NSRange rg={3,5};//第一参数是起始位置第二个参数是长度 //NSRange rg; //rg.location=3; //rg.length=5; //NSRange rg={.location=3,.length=5}; //常用下面的方式定义 NSRange rg2=NSMakeRange(3,5);//使用NSMakeRange定义一个NSRange //打印NSRange可以使用Foundation中方法 NSLog(@"rg2 is %@", NSStringFromRange(rg2));//注意不能直接NSLog(@"rg2 is %@", rg2),因为rg2不是对象(准确的说%@是指针)而是结构体 } /*NSPoint表示一个点*/ void test2(){ NSPoint p=NSMakePoint(10, 15);//NSPoint其实就是CGPoint //这种方式比较常见 NSPoint p2=CGPointMake(10, 15); NSLog(NSStringFromPoint(p2)); } /*NSSize表示大小*/ void test3(){ NSSize s=NSMakeSize(10, 15);//NSSize其实就是CGSize //这种方式比较常见 CGSize s2=CGSizeMake(10, 15); NSLog(NSStringFromSize(s2)); } /*NSRect表示一个矩形*/ void test4(){ NSRect r=NSMakeRect(10, 5, 100, 200);//NSRect其实就是CGRect //这种方式比较常见 NSRect r2=CGRectMake(10, 5, 100, 200); NSLog(NSStringFromRect(r2)); } int main(int argc, const char * argv[]) { @autoreleasepool { test1(); test2(); test3(); test4(); } return 0; }可以看到对于常用结构体在Foundation框架中都有一个对应的make方法进行创建,这也是我们日后比较常用的操作;而且与之对应的还都有一个NSStringFromXX方法来进行字符串转换,方便我们调试。上面也提到NSSize其实就是CGSize,NSRect其实就是CGRect,我们可以通过查看代码进行确认,例如NSSize定义:
继续查看CGSize的代码:
日期
接下来熟悉一下Foundation框架中日期的操作
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #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语言中简单的多,在下面的例子中你将看到字符串的初始化、大小写转化、后缀前缀判断、字符串比较、字符串截取、字符串转换等,通过下面的例子我们基本可以掌握常用的字符串操作(注意这些内容虽然基本,但却是十分常用的操作,需要牢记):
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> /**字符串操作*/ void test1(){ char *str1="C string";//这是C语言创建的字符串 NSString *str2=@"OC string";//ObjC字符串需要加@,并且这种方式创建的对象不需要自己释放内存 //下面的创建方法都应该释放内存 NSString *str3=[[NSString alloc] init]; str3=@"OC string"; NSString *str4=[[NSString alloc] initWithString:@"Objective-C string"]; NSString *str5=[[NSString alloc] initWithFormat:@"age is %i,name is %.2f",19,1.72f]; NSString *str6=[[NSString alloc] initWithUTF8String:"C string"];//C语言的字符串转换为ObjC字符串 //以上方法都有对应静态方法(一般以string开头),不需要管理内存(系统静态方法一般都是自动释放) NSString *str7=[NSString stringWithString:@"Objective-C string"]; } void test2(){ NSLog(@"\"Hello world!\" to upper is %@",[@"Hello world!" uppercaseString]); //结果:"Hello world!" to upper is HELLO WORLD! NSLog(@"\"Hello world!\" to lowwer is %@",[@"Hello world!" lowercaseString]); //结果:"Hello world!" to lowwer is hello world! //首字母大写,其他字母小写 NSLog(@"\"Hello world!\" to capitalize is %@",[@"Hello world!" capitalizedString]); //结果:"Hello world!" to capitalize is Hello World! BOOL result= [@"abc" isEqualToString:@"aBc"]; NSLog(@"%i",result); //结果:0 NSComparisonResult result2= [@"abc" compare:@"aBc"];//如果是[@"abc" caseInsensitiveCompare:@"aBc"]则忽略大小写比较 if(result2==NSOrderedAscending){ NSLog(@"left<right."); }else if(result2==NSOrderedDescending){ NSLog(@"left>right."); }else if(result2==NSOrderedSame){ NSLog(@"left=right."); } //结果:left>right. } void test3(){ NSLog(@"has prefix ab? %i",[@"abcdef" hasPrefix:@"ab"]); //结果:has prefix ab? 1 NSLog(@"has suffix ab? %i",[@"abcdef" hasSuffix:@"ef"]); //结果:has suffix ab? 1 NSRange range=[@"abcdefabcdef" rangeOfString:@"cde"];//注意如果遇到cde则不再往后面搜索,如果从后面搜索或其他搜索方式可以设置第二个options参数 if(range.location==NSNotFound){ NSLog(@"not found."); }else{ NSLog(@"range is %@",NSStringFromRange(range)); } //结果:range is {2, 3} } //字符串分割 void test4(){ NSLog(@"%@",[@"abcdef" substringFromIndex:3]);//从第三个索引开始(包括第三个索引对应的字符)截取到最后一位 //结果:def NSLog(@"%@",[@"abcdef" substringToIndex:3]);////从0开始截取到第三个索引(不包括第三个索引对应的字符) //结果:abc NSLog(@"%@",[@"abcdef" substringWithRange:NSMakeRange(2, 3)]); //结果:cde NSString *str1=@"12.abcd.3a"; NSArray *array1=[str1 componentsSeparatedByString:@"."];//字符串分割 NSLog(@"%@",array1); /*结果: ( 12, abcd, 3a ) */ } //其他操作 void test5(){ NSLog(@"%i",[@"12" intValue]);//类型转换 //结果:12 NSLog(@"%zi",[@"hello world,世界你好!" length]);//字符串长度注意不是字节数 //结果:17 NSLog(@"%c",[@"abc" characterAtIndex:0]);//取出制定位置的字符 //结果:a const char *s=[@"abc" UTF8String];//转换为C语言字符串 NSLog(@"%s",s); //结果:abc } int main(int argc, const char * argv[]) { test1(); test2(); test3(); test4(); test5(); return 0; }
注意:上面代码注释中提到的需要释放内存指的是在MRC下的情况,当然本质上在ARC下也需要释放,只是这部分代码编译器会自动创建。
扩展--文件操作
在ObjC中路径、文件读写等操作是利用字符串来完成的,这里通过几个简单的例子来演示(首先在桌面上新建一个test.txt文件,里面存储的内容是”hello world,世界你好!”)
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> void test1(){ //读取文件内容 NSString *path=@"/Users/kenshincui/Desktop/test.txt"; NSString *str1=[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; //注意上面也可以使用gb2312 gbk等,例如kCFStringEncodingGB_18030_2000,但是需要用CFStringConvertEncodingToNSStringEncoding转换 NSLog(@"str1 is %@",str1); //结果:str1 is hello world,世界你好! //上面我们看到了读取文件,但并没有处理错误,当然在ObjC中可以@try @catch @finnally但通常我们并不那么做 //由于我们的test.txt中有中文,所以使用下面的编码读取会报错,下面的代码演示了错误获取的过程 NSError *error; NSString *str2=[NSString stringWithContentsOfFile:path encoding:kCFStringEncodingGB_18030_2000 error:&error];//注意这句话中的error变量是**error,就是指针的指针那就是指针的地址,由于error就是一个指针此处也就是error的地址&error,具体原因见下面补充 if(error){ NSLog(@"read error ,the error is %@",error); }else{ NSLog(@"read success,the file content is %@",str2); } //结果: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} //读取文件内容还有一种方式就是利用URl,它除了可以读取本地文件还可以读取网络文件 //NSURL *url=[NSURL URLWithString:@"file:///Users/kenshincui/Desktop/test.txt"]; NSURL *url=[NSURL URLWithString:@"http://www.apple.com"]; NSString *str3=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; NSLog(@"str3 is %@",str3); } void test2(){ //下面是文件写入 NSString *path1=@"/Users/kenshincui/Desktop/test2.txt"; NSError *error1; NSString *str11=@"hello world,世界你好!"; [str11 writeToFile:path1 atomically:YES encoding:NSUTF8StringEncoding error:&error1];//automically代表一次性写入,如果写到中间出错了最后就全部不写入 if(error1){ NSLog(@"write fail,the error is %@",[error1 localizedDescription]);//调用localizedDescription是只打印关键错误信息 }else{ NSLog(@"write success!"); } //结果:write success! } //路径操作 void test3(){ NSMutableArray *marray=[NSMutableArray array];//可变数组 [marray addObject:@"Users"]; [marray addObject:@"KenshinCui"]; [marray addObject:@"Desktop"]; NSString *path=[NSString pathWithComponents:marray]; NSLog(@"%@",path);//字符串拼接成路径 //结果:Users/KenshinCui/Desktop NSLog(@"%@",[path pathComponents]);//路径分割成数组 /*结果: ( Users, KenshinCui, Desktop ) */ NSLog(@"%i",[path isAbsolutePath]);//是否绝对路径(其实就是看字符串是否以“/”开头) //结果:0 NSLog(@"%@",[path lastPathComponent]);//取得最后一个目录 //结果:Desktop NSLog(@"%@",[path stringByDeletingLastPathComponent]);//删除最后一个目录,注意path本身是常量不会被修改,只是返回一个新字符串 //结果:Users/KenshinCui NSLog(@"%@",[path stringByAppendingPathComponent:@"Documents"]);//路径拼接 //结果:Users/KenshinCui/Desktop/Documents } //扩展名操作 void test4(){ NSString *path=@"Users/KenshinCui/Desktop/test.txt"; NSLog(@"%@",[path pathExtension]);//取得扩展名,注意ObjC中扩展名不包括"." //结果:txt NSLog(@"%@",[path stringByDeletingPathExtension]);//删除扩展名,注意包含"." //结果:Users/KenshinCui/Desktop/test NSLog(@"%@",[@"Users/KenshinCui/Desktop/test" stringByAppendingPathExtension:@"mp3"]);//添加扩展名 //结果:Users/KenshinCui/Desktop/test.mp3 } int main(int argc, const char * argv[]) { test1(); test2(); test3(); test4(); return 0; }
注意:在上面的例子中我们用到了可变数组,下面会专门介绍。
可变字符串
我们知道在字符串操作过程中我们经常希望改变原来的字符串,当然这在C语言中实现比较复杂,但是ObjC为我们提供了新的可变字符串类NSMutableString,它是NSString的子类。
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { /*可变字符串,注意NSMutableString是NSString子类*/ //注意虽然initWithCapacity分配字符串大小,但是不是绝对的不可以超过此范围,声明此变量对性能有好处 NSMutableString *str1= [[NSMutableString alloc] initWithCapacity:10]; [str1 setString:@"hello"];//设置字符串 NSLog(@"%@",str1); //结果:hello [str1 appendString:@",world!"];//追加字符串 NSLog(@"%@",str1); //结果:hello,world! [str1 appendFormat:@"我的年龄是%i。dear,I love you.",18]; NSLog(@"%@",str1); //结果:hello,world!我的年龄是18。dear,I love you. //替换字符串 NSRange range=[str1 rangeOfString:@"dear"]; [str1 replaceCharactersInRange:range withString:@"Honey"]; NSLog(@"%@",str1); //结果:hello,world!我的年龄是18。Honey,I love you. //插入字符串 [str1 insertString:@"My name is Kenshin." atIndex:12]; NSLog(@"%@",str1); //结果:hello,world!My name is Kenshin.我的年龄是18。Honey,I love you. //删除指定字符串 [str1 deleteCharactersInRange:[str1 rangeOfString:@"My name is Kenshin."]];//删除指定范围的字符串 NSLog(@"%@",str1); //结果:hello,world!我的年龄是18。Honey,I love you. return 0; }
数组
不可变数组
下面将演示常用的数组操作:初始化、数组对象的方法执行、数组元素的遍历、在原有数组基础上产生新数组、数组排序等
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> #import "Person.h" void test1(){ //NSArray长度不可变所以初始化的时候就赋值,并且最后以nil结尾 //此外需要注意NSArray不能存放C语言的基础类型 NSObject *obj=[[NSObject alloc]init]; //NSArray *array1=[[NSArray alloc] initWithObjects:@"abc",obj,@"cde",@"opq", nil]; NSArray *array1=[NSArray arrayWithObjects:@"abc",obj,@"cde",@"opq",@25, nil]; NSLog(@"%zi",array1.count);//数组长度,结果:5 NSLog(@"%i",[array1 containsObject:@"cde"]);//是否包含某个对象,结果:1 NSLog(@"%@",[array1 lastObject]);//最后一个对象,结果:25 NSLog(@"%zi",[array1 indexOfObject:@"abc"]);//对象所在的位置:0 Person *person1=[Person personWithName:@"Kenshin"]; Person *person2=[Person personWithName:@"Kaoru"]; Person *person3=[Person personWithName:@"Rosa"]; NSArray *array2=[[NSArray alloc]initWithObjects:person1,person2,person3, nil]; [array2 makeObjectsPerformSelector:@selector(showMessage:) withObject:@"Hello,world!"];//执行所有元素的showMessage方法,后面的参数最多只能有一个 /*结果: My name is Kenshin,the infomation is "Hello,world!". My name is Kaoru,the infomation is "Hello,world!". My name is Rosa,the infomation is "Hello,world!". */ } //数组的遍历 void test2(){ NSObject *obj=[[NSObject alloc]init]; NSArray *array=[[NSArray alloc] initWithObjects:@"abc",obj,@"cde",@"opq",@25, nil]; //方法1 for(int i=0,len=array.count;i<len;++i){ NSLog(@"method1:index %i is %@",i,[array objectAtIndex:i]); } /*结果: method1:index 0 is abc method1:index 1 is <NSObject: 0x100106de0> method1:index 2 is cde method1:index 3 is opq method1:index 4 is 25 */ //方法2 for(id obj in array){ NSLog(@"method2:index %zi is %@",[array indexOfObject:obj],obj); } /*结果: method2:index 0 is abc method2:index 1 is <NSObject: 0x100602f00> method2:index 2 is cde method2:index 3 is opq method2:index 4 is 25 */ //方法3,利用代码块方法 [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"method3:index %zi is %@",idx,obj); if(idx=
请发表评论