咱們前面的章節中就一直新建Cocoa Class,那麼Cocoa究竟是什麼,它和咱們前面以及後面要講的內容到底有什麼關係呢?Objective-C開發中常常用到NSObject,那麼這個對象究竟是誰?它爲何又出如今Objective-C中間呢?今天咱們將揭開這層面紗,重點分析在IOS開發中一個重要的框架Foundation,今天的主要內容有:ios
爲何前面說的內容中新建一個類的時候咱們都是選擇Cocoa Class呢?Cocoa是什麼呢?spring
Cocoa不是一種編程語言(它能夠運行多種編程語言),它也不是一個開發工具(經過命令行咱們仍然能夠開發Cocoa程序),它是建立Mac OS X和IOS程序的原生面向對象API,爲這二者應用提供了編程環境。數據庫
咱們一般稱爲「Cocoa框架」,事實上Cocoa自己是一個框架的集合,它包含了衆多子框架,其中最重要的要數「Foundation」和「UIKit」。前者是框架的基礎,和界面無關,其中包含了大量經常使用的API;後者是基礎的UI類庫,之後咱們在IOS開發中會常常用到。這兩個框架在系統中的位置以下圖:編程
其實全部的Mac OS X和IOS程序都是由大量的對象構成,而這些對象的根對象都是NSObject,NSObject就處在Foundation框架之中,具體的類結構以下:api
一般咱們會將他們分爲幾類:數組
UIKit主要用於界面構架,這裏咱們不妨也看一下它的類結構:網絡
在Foundation中定義了不少經常使用結構體類型來簡化咱們的平常開發,這些結構體徹底採用Objective-C定義,和咱們本身定義的結構體沒有任何區別,之因此由框架爲咱們提供徹底是爲了簡化咱們的開發。經常使用的結構體有NSRange、NSPoint、NSSize、NSRect等app
// // 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==2){//當idx=2時設置*stop爲YES中止遍歷 *stop=YES; } }]; /*結果: method3:index 0 is abc method3:index 1 is <NSObject: 0x100106de0> method3:index 2 is cde */ //方法4,利用迭代器 //NSEnumerator *enumerator= [array objectEnumerator];//得到一個迭代器 NSEnumerator *enumerator=[array reverseObjectEnumerator];//獲取一個反向迭代器 //NSLog(@"all:%@",[enumerator allObjects]);//獲取全部迭代對象,注意調用完此方法迭代器就遍歷完了,下面的nextObject就沒有值了 id obj2=nil; while (obj2=[enumerator nextObject]) { NSLog(@"method4:%@",obj2); } /*結果: method4:25 method4:opq method4:cde method4:<NSObject: 0x100106de0> method4:abc */ } //數組派生出新的數組 void test3(){ NSArray *array=[NSArray arrayWithObjects:@"1",@"2",@"3", nil]; NSArray *array2=[array arrayByAddingObject:@"4"];//注意此時array並無變 NSLog(@"%@",array2); /*結果: ( 1, 2, 3, 4 ) */ NSLog(@"%@",[array2 arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:@"5",@"6", nil]]);//追加造成新的數組 /*結果: ( 1, 2, 3, 4, 5, 6 ) */ NSLog(@"%@",[array2 subarrayWithRange:NSMakeRange(1, 3)]);//根據必定範圍取得生成一個新的數組 /*結果: ( 2, 3, 4 ) */ NSLog(@"%@",[array componentsJoinedByString:@","]);//數組鏈接,造成一個字符串 //結果:1,2,3 //讀寫文件 NSString *path=@"/Users/KenshinCui/Desktop/array.xml"; [array writeToFile:path atomically:YES]; NSArray *array3=[NSArray arrayWithContentsOfFile:path]; NSLog(@"%@",array3); /*結果: ( 1, 2, 3 ) */ } //數組排序 void test4(){ //方法1,使用自帶的比較器 NSArray *array=[NSArray arrayWithObjects:@"3",@"1",@"2", nil]; NSArray *array2= [array sortedArrayUsingSelector:@selector(compare:)]; NSLog(@"%@",array2); /*結果: ( 1, 2, 3 ) */ //方法2,本身定義比較器 Person *person1=[Person personWithName:@"Kenshin"]; Person *person2=[Person personWithName:@"Kaoru"]; Person *person3=[Person personWithName:@"Rosa"]; NSArray *array3=[NSArray arrayWithObjects:person1,person2,person3, nil]; NSArray *array4=[array3 sortedArrayUsingSelector:@selector(comparePerson:)]; NSLog(@"%@",array4); /*結果: ( "name=Kaoru", "name=Kenshin", "name=Rosa" ) */ //方法3使用代碼塊 NSArray *array5=[array3 sortedArrayUsingComparator:^NSComparisonResult(Person *obj1, Person *obj2) { return [obj2.name compare:obj1.name];//降序 }]; NSLog(@"%@",array5); /*結果: ( "name=Rosa", "name=Kenshin", "name=Kaoru" ) */ //方法4 經過描述器定義排序規則 Person *person4=[Person personWithName:@"Jack"]; Person *person5=[Person personWithName:@"Jerry"]; Person *person6=[Person personWithName:@"Tom"]; Person *person7=[Person personWithName:@"Terry"]; NSArray *array6=[NSArray arrayWithObjects:person4,person5,person6,person7, nil]; //定義一個排序描述 NSSortDescriptor *personName=[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; NSSortDescriptor *accountBalance=[NSSortDescriptor sortDescriptorWithKey:@"account.balance" ascending:YES]; NSArray *des=[NSArray arrayWithObjects:personName,accountBalance, nil];//先按照person的name排序再按照account的balance排序 NSArray *array7=[array6 sortedArrayUsingDescriptors:des]; NSLog(@"%@",array7); /*結果: ( "name=Jack", "name=Jerry", "name=Terry", "name=Tom" ) */ } int main(int argc, const char * argv[]) { test1(); test2(); test3(); test4(); 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(){ 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; }
字典在咱們平常開發中也是比較經常使用的,經過下面的代碼咱們看一下在ObjC中的字典的經常使用操做:初始化、遍歷、排序
// // 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(){ 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) {//注意對於字典for遍歷循環的是key NSLog(@"%@=%@",key,[dic1 objectForKey:key]); } /*結果: d=2 b=2 c=3 a=1 */ //遍歷2 NSEnumerator *enumerator=[dic1 keyEnumerator];//還有值的迭代器[dic1 objectEnumerator] 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; } */ //注意,一個字典的key或value添加到字典中時計數器+1;字典釋放時調用key或value的release一次,計數器-1 } int main(int argc, const char * argv[]) { test1(); test2(); test3(); test4(); return 0; }
注意:同數組同樣,無論是可變字典仍是不可變字典初始化元素後面必須加上nil以表示結束。
其實從上面的例子中咱們也能夠看到,數組和字典中只能存儲對象類型,其餘基本類型和結構體是沒有辦法放到數組和字典中的,固然你也是沒法給它們發送消息的(也就是說有些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;
簡單看一個例子
// // 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(){ //包裝類NSNumber,能夠包裝基本類型可是沒法包裝結構體類型 NSNumber *number1=[NSNumber numberWithChar:'a'];//'a'是一個C語言的char類型咱們沒法放倒NSArray中,可是咱們能夠經過NSNumber包裝 NSArray *array1=[NSArray arrayWithObject:number1]; NSLog(@"%@",array1); /*結果: ( 97 ) */ NSNumber *number2= [array1 lastObject]; NSLog(@"%@",number2);//返回的不是基本類型,結果:97 char char1=[number2 charValue];//number轉化爲char NSLog(@"%c",char1); //結果:a } int main(int argc, const char * argv[]) { test1(); return 0; }
上面咱們看到了基本數據類型的裝箱和拆箱過程,那麼結構體呢?這個時候咱們須要引入另一個類型NSValue,其實上面的NSNumber就是NSValue的子類,它包裝了一些基本數據類型的經常使用裝箱、拆箱方法,當要對結構體進行裝箱、拆箱操做咱們須要使用NSValue,NSValue能夠對任何數據類型進行裝箱、拆箱操做。
事實上對於經常使用的結構體Foundation已經爲咱們提供好了具體的裝箱方法:
+(NSValue *)valueWithPoint:(NSPoint)point;
+(NSValue *)valueWithSize:(NSSize)size;
+(NSValue *)valueWithRect:(NSRect)rect;
對應的拆箱方法:
-(NSPoint)pointValue;
-(NSSize)sizeValue;
-(NSRect)rectValue;
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> //NSNumber是NSValue的子類,而NSValue能夠包裝任何類型,包括結構體 void test1(){ CGPoint point1=CGPointMake(10, 20); NSValue *value1=[NSValue valueWithPoint:point1];//對於系統自帶類型通常都有直接的方法進行包裝 NSArray *array1=[NSArray arrayWithObject:value1];//放倒數組中 NSLog(@"%@",array1); /*結果: ( "NSPoint: {10, 20}" ) */ NSValue *value2=[array1 lastObject]; CGPoint point2=[value2 pointValue];//一樣對於系統自帶的結構體有對應的取值方法(例如本例pointValue) NSLog(@"x=%f,y=%f",point2.x,point2.y);//結果:x=10.000000,y=20.000000 } int main(int argc, const char * argv[]) { test1(); return 0; }
那麼若是是咱們自定義的結構體類型呢,這個時候咱們須要使用NSValue以下方法進行裝箱:
+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
調用下面的方法進行拆箱:
-(void)getValue:(void *)value;
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> typedef struct { int year; int month; int day; } Date; //NSNumber是NSValue的子類,而NSValue能夠包裝任何類型,包括結構體 void test1(){ //若是咱們本身定義的結構體包裝 Date date={2014,2,28}; char *type=@encode(Date); NSValue *value3=[NSValue value:&date withObjCType:type];//第一參數傳遞結構體地址,第二個參數傳遞類型字符串 NSArray *array2=[NSArray arrayWithObject:value3]; NSLog(@"%@",array2); /*結果: ( "<de070000 02000000 1c000000>" ) */ Date date2; [value3 getValue:&date2];//取出對應的結構體,注意沒有返回值 //[value3 objCType]//取出包裝內容的類型 NSLog(@"%i,%i,%i",date2.year,date2.month,date2.day); //結果:2014,2,28 } int main(int argc, const char * argv[]) { test1(); return 0; }
經過前面的介紹你們都知道不管在數組仍是在字典中都必須以nil結尾,不然數組或字典沒法判斷是否這個數組或字典已經結束(與C語言中的字符串比較相似,C語言中定義字符串後面必須加一個」\0」)。可是咱們有時候確實想在數據或字典中存儲nil值而不是做爲結束標記怎麼辦呢?這個時候須要使用NSNull,這個類是一個單例,只有一個null方法。簡單看一下:
// // 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[]) { NSNull *nl=[NSNull null];//注意這是一個對象,是一個單例,只有一個方法null建立一個對象 NSNull *nl2=[NSNull null]; NSLog(@"%i",nl==nl2);//因爲是單例因此地址相等,結果:1 NSArray *array1=[NSArray arrayWithObjects:@"abc",nl,@123, nil]; NSLog(@"%@",array1); /*結果: ( abc, "<null>", 123 ) */ return 0; }
咱們知道在ObjC中不少關鍵字前都必須加上@符號,例如@protocol、@property等,固然ObjC中的字符串必須使用@符號,還有就是%@能夠表示輸出一個對象。其實@符號在新版的ObjC中還有一個做用:裝箱。
相信聰明的童鞋在前面的例子中已經看到了,這裏簡單的介紹一下(在下面的演示中你也將看到不少ObjC新特性)。
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> typedef enum { spring, summer, autumn, winter } Season; int main(int argc, const char * argv[]) { /*裝箱*/ NSNumber *number1=@100; NSArray *array1=[NSArray arrayWithObjects:number1,@"abc",@16,@'A',@16.7,@YES, nil]; NSLog(@"%@",array1); /*結果: ( 100, abc, 16, 65, "16.7" 1 ) */ NSNumber *number2=@(1+2*3); NSLog(@"%@",number2); //結果:7 NSNumber *number3=@(autumn); NSLog(@"%@",number3); //結果:2 NSArray *array2=@[@"abc",@16,@'A',@16.7,@YES];//使用這種方式最後不用添加nil值了 NSLog(@"%@",array2[2]); //結果:65 NSMutableArray *array3=[NSMutableArray arrayWithArray:array2]; array3[0]=@"def"; NSLog(@"%@",array3[0]); //結果:def NSDictionary *dic1=@{@"a":@123,@"b":@'c',@"c":@YES}; NSLog(@"%@",dic1); /*結果: { a = 123; b = 99; c = 1; } */ NSMutableDictionary *dic2=[NSMutableDictionary dictionaryWithDictionary:dic1]; dic2[@"a"]=@456; NSLog(@"%@",dic2[@"a"]);//結果:456 return 0; }
因爲ObjC動態性,在ObjC中實現反射能夠說是至關簡單,下面代碼中演示了經常使用的反射操做,具體做用也都在代碼中進行了註釋說明:
Account.h
// // Account.h // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> @interface Account : NSObject @property (nonatomic,assign) double balance; @end
Account.m
// // Account.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "Account.h" @implementation Account @end
Person.h
// // Person.h // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> @class Account; @interface Person : NSObject @property (nonatomic,copy) NSString *name; @property (nonatomic,retain) Account *account; -(Person *)initWithName:(NSString *)name; +(Person *)personWithName:(NSString *)name; -(void)showMessage:(NSString *)infomation; //本身實現對象比較方法 -(NSComparisonResult)comparePerson:(Person *)person; @end
Person.m
// // Person.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "Person.h" @implementation Person -(Person *)initWithName:(NSString *)name{ if(self=[super init]){ self.name=name; } return self; } +(Person *)personWithName:(NSString *)name{ Person *person=[[Person alloc]initWithName:name]; return person; } -(void)showMessage:(NSString *)infomation{ NSLog(@"My name is %@,the infomation is \"%@\".",_name,infomation); } //本身實現對象比較方法 -(NSComparisonResult)comparePerson:(Person *)person{ return [_name compare:person.name]; } -(NSString *)description{ return [NSString stringWithFormat:@"name=%@",_name]; } @end
main.m
// // 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" int main(int argc, const char * argv[]) { /*經常使用方法*/ Person *person1=[Person personWithName:@"Kenshin"]; NSLog(@"%i",[person1 isKindOfClass:[NSObject class]]); //判斷一個對象是否爲某種類型(若是是父類也返回YES),結果:1 NSLog(@"%i",[person1 isMemberOfClass:[NSObject class]]); //判斷一個對象是不是某個類的實例化對象,結果:0 NSLog(@"%i",[person1 isMemberOfClass:[Person class]]); //結果:1 NSLog(@"%i",[person1 conformsToProtocol:@protocol(NSCopying)]);//是否實現了某個協議,結果:0 NSLog(@"%i",[person1 respondsToSelector:@selector(showMessage:)]);//是否存在某個方法,結果:1 [person1 showMessage:@"Hello,world!"];//直接調用一個方法 [person1 performSelector:@selector(showMessage:) withObject:@"Hello,world!"]; //動態調用一個方法,注意若是有參數那麼參數類型只能爲ObjC對象,而且最多隻能有兩個參數 /*反射*/ //動態生成一個類 NSString *className=@"Person"; Class myClass=NSClassFromString(className);//根據類名生成類 Person *person2=[[myClass alloc]init]; //實例化 person2.name=@"Kaoru"; NSLog(@"%@",person2);//結果:name=Kaoru //類轉化爲字符串 NSLog(@"%@,%@",NSStringFromClass(myClass),NSStringFromClass([Person class])); //結果:Person,Person //調用方法 NSString *methodName=@"showMessage:"; SEL mySelector=NSSelectorFromString(methodName); Person *person3=[[myClass alloc]init]; person3.name=@"Rosa"; [person3 performSelector:mySelector withObject:@"Hello,world!"]; //結果:My name is Rosa,the infomation is "Hello,world!". //方法轉化爲字符串 NSLog(@"%@",NSStringFromSelector(mySelector)); //結果:showMessage: return 0; }
對象拷貝操做也比較常見,在ObjC中有兩種方式的拷貝:copy和mutablecopy,這兩種方式都將產生一個新的對象,只是後者產生的是一個可變對象。在ObjC中若是要想實現copy或者mutablecopy操做須要實現NSCopy或者NSMutableCopy協議,拷貝操做產生的新的對象默認引用計數器是1,在非ARC模式下咱們應該對這個對象進行內存管理。在熟悉這兩種操做以前咱們首先須要弄清兩個概念:深複製(或深拷貝)和淺複製(或淺拷貝)。
注:
指針拷貝:拷貝的是指針自己(也就是具體對象的地址)而不是指向的對象內容自己。
對象複製:對象複製指的是複製內容是對象自己而不是對象的地址。
徹底複製:上面說了深複製和淺複製,既然深複製是至少一個對象複製是對象內容複製,那麼若是全部複製都是對象內容複製那麼這個複製就叫徹底複製。
對比copy和mutablecopy其實前面咱們一直還用到一個操做是retain,它們之間的關係以下:
retain:始終採起淺複製,引用計數器會加1,返回的對象和被複制對象是同一個對象1(也就是說這個對象的引用多了一個,或者說是指向這個對象的指針多了一個);
copy:對於不可變對象copy採用的是淺複製,引用計數器加1(其實這是編譯器進行了優化,既然原來的對象不可變,複製以後的對象也不可變那麼就沒有必要再從新建立一個對象了);對於可變對象copy採用的是深複製,引用計數器不變(原來的對象是可變,如今要產生一個不可變的固然得從新產生一個對象);
mutablecopy:不管是可變對象仍是不可變對象採起的都是深複製,引用計數器不變(若是從一個不可變對象產生一個可變對象天然不用說兩個對象絕對不同確定是深複製;若是從一個可變對象產生出另外一個可變對象,那麼當其中一個對象改變天然不但願另外一個對象改變,固然也是深複製)。
注:
可變對象:當值發生了改變,那麼地址也隨之發生改變;
不可變對象:當值發生了改變,內容首地址不發生變化;
引用計數器:用於計算一個對象有幾個指針在引用(有幾個指針變量指向同一個內存地址);
// // 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 *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; }
爲了方便你們理解上面的代碼,這裏以圖形畫出str一、str二、str三、str4在內存中的存儲狀況:
從上面能夠清楚的看到str1和str3同時指向同一個對象,所以這個對象的引用計數器是2(能夠看到兩箭頭指向那個對象),str2和str4都是兩個新的對象;另外ObjC引入對象拷貝是爲了改變一個對象不影響另外一個對象,可是咱們知道NSString自己就不能改變那麼即便我從新複製一個對象也沒有任何意義,所以爲了性能着想若是經過copy方法產生一個NSString時ObjC不會再複製一個對象而是將新變量指向同一個對象。
注意網上不少人支招在ARC模式下能夠利用_objc_rootRetainCount()或者CFGetRetainCount()取得retainCount都是不許確的,特別是在對象拷貝操做以後你會發現兩者取值也是不一樣的,所以若是你們要查看retainCount最好仍是暫時關閉ARC。
要想支持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 14-2-16. // Copyright (c) 2014年 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 14-2-16. // Copyright (c) 2014年 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 14-2-16. // Copyright (c) 2014年 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對象。經過圖形表示以下:
上面test2的寫法純屬爲了讓你們瞭解複製的原理和本質,實際開發中咱們不多會遇到這種狀況,首先咱們通常定義name的話可能用的是NSString類型,根本也不能修改;其次咱們定義字符串類型的話通常使用(copy)參數,一樣能夠避免這個問題(由於NSMutableString的copy是深複製)。那麼若是咱們非要使用NSMutabeString同時不使用屬性的copy參數如何解決這個問題呢?答案就是使用深複製,將-(id)copyWithZone:(NSZone *)zone方法中person1.name=_name改成,person1.name=[_name copy];或person1.name=[_name mutablecopy]便可,這樣作也正好知足咱們上面對於深複製的定義。
在好多語言中字符串都是一個特殊的對象,在ObjC中也不例外。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,char *argv[]){ NSString *str1=@"Kenshin"; NSLog(@"retainCount(str1)=%i",(unsigned long)str1.retainCount); //結果:-1 [str1 retain]; NSLog(@"retainCount(str1)=%i",(unsigned long)str1.retainCount); //結果:-1 NSString *str2=[NSString stringWithString:@"Kaoru"]; NSLog(@"retainCount(str2)=%i",str2.retainCount); //結果:-1 [str1 retain]; NSLog(@"retainCount(str2)=%i",str2.retainCount); //結果:-1 NSString *str2_1=[NSString stringWithString:[NSString stringWithFormat:@"Kaoru %@",@"sun"]]; NSLog(@"retainCount(str2_1)=%i",str2_1.retainCount);//結果:2 [str2_1 release]; [str2_1 release]; NSString *str3=[NSString stringWithFormat:@"Rosa %@",@"Sun"]; NSLog(@"retainCount(str3)=%i",str3.retainCount); //結果:1 [str3 retain]; NSLog(@"retainCount(str3)=%i",str3.retainCount); //結果:2 [str3 release]; [str3 release]; NSString *str4=[NSString stringWithUTF8String:"Jack"]; NSLog(@"retainCount(str4)=%i",str4.retainCount); //結果:1 [str4 retain]; NSLog(@"retainCount(str4)=%i",str4.retainCount); //結果:2 [str4 release]; [str4 release]; NSString *str5=[NSString stringWithCString:"Tom" encoding:NSUTF8StringEncoding]; NSLog(@"retainCount(str5)=%i",str5.retainCount); //結果:1 [str5 retain]; NSLog(@"retainCount(str5)=%i",str5.retainCount); //結果:2 [str5 release]; [str5 release]; NSMutableString *str6=@"Jerry"; NSLog(@"retainCount(str6)=%i",str6.retainCount); //結果:-1 [str6 retain]; NSLog(@"retainCount(str6)=%i",str6.retainCount); //結果:-1 [str6 release]; [str6 release]; NSMutableArray *str7=[NSMutableString stringWithString:@"Lily"]; NSLog(@"retainCount(str7)=%i",str7.retainCount); //結果:1 [str7 retain]; NSLog(@"retainCount(str7)=%i",str7.retainCount); //結果:2 [str7 release]; [str7 release]; return 0; }
看完上面的例子若是不瞭解NSString的處理你也許會有點奇怪(注意上面的代碼請在Xcode5下運行)?請看下面的解釋
後記:注意上面這段代碼的運行結果是在Xcode5中運行的結果,事實上針對最新的Xcode6因爲LLVM的優化,只有str2_1和str7的引用計數器爲1(str7 retain一次後第二次爲2),其餘均爲-1。
在今天的最後一節內容中讓咱們看一下Foundation中文件操做,下面將以一個例子進行說明:
// // 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(){ //文件管理器是專門用於文件管理的類 NSFileManager *manager=[NSFileManager defaultManager]; //得到當前程序所在目錄(固然能夠改變) NSString *currentPath=[manager currentDirectoryPath]; NSLog(@"current path is :%@",currentPath); //結果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug //建立目錄 NSString *myPath=@"/Users/kenshincui/Desktop/myDocument"; BOOL result= [manager createDirectoryAtPath:myPath withIntermediateDirectories:YES attributes:nil error:nil]; if(result==NO){ NSLog(@"Couldn't create directory!"); } //目錄重命名,若是須要刪除目錄只要調用removeItemAtPath:<#(NSString *)#> error:<#(NSError **)#> NSError *error; NSString *newPath=@"/Users/kenshincui/Desktop/myNewDocument"; if([manager moveItemAtPath:myPath toPath:newPath error:&error]==NO){ NSLog(@"Rename directory failed!Error infomation is:%@",error); } //改變當前目錄 if([manager changeCurrentDirectoryPath:newPath]==NO){ NSLog(@"Change current directory failed!"); } NSLog(@"current path is :%@",[manager currentDirectoryPath]); //結果:current path is :/Users/kenshincui/Desktop/myNewDocument //遍歷整個目錄 NSString *path; NSDirectoryEnumerator *directoryEnumerator= [manager enumeratorAtPath:newPath]; while (path=[directoryEnumerator nextObject]) { NSLog(@"%@",path); } /*結果: documents est.txt */ //或者這樣遍歷 NSArray *paths= [manager contentsOfDirectoryAtPath:newPath error:nil]; NSObject *p; for (p in paths) { NSLog(@"%@",p); } /*結果: documents est.txt */ } /*文件操做*/ void test2(){ NSFileManager *manager=[NSFileManager defaultManager]; NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test.txt"; NSString *filePath2=@"/Users/kenshincui/Desktop/test.txt"; NSString *newPath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt"; //判斷文件是否存在,這個方法也能夠判斷目錄是否存在,這要後面的參數設置位YES if ([manager fileExistsAtPath:filePath isDirectory:NO]) { NSLog(@"File exists!"); } //文件是否可讀 if([manager isReadableFileAtPath:filePath]){ NSLog(@"File is readable!"); } //判斷兩個文件內容是否相等 if ([manager contentsEqualAtPath:filePath andPath:filePath2]) { NSLog(@"file1 equals file2"); } //文件重命名,方法相似於目錄重命名 if (![manager moveItemAtPath:filePath toPath:newPath error:nil]) { NSLog(@"Rename file1 failed!"); } //文件拷貝 NSString *filePath3=@"/Users/kenshincui/Desktop/test3.txt"; if(![manager copyItemAtPath:newPath toPath:filePath3 error:nil]){ NSLog(@"Copy failed!"); } //讀取文件屬性 NSDictionary *attributes; if ((attributes=[manager attributesOfItemAtPath:newPath error:nil])==nil) { NSLog(@"Read attributes failed!"); } for (NSObject *key in attributes) { NSLog(@"%@=%@",key,attributes[key]); } /*結果: NSFileOwnerAccountID=501 NSFileHFSTypeCode=0 NSFileSystemFileNumber=1781953 NSFileExtensionHidden=0 NSFileSystemNumber=16777218 NSFileSize=27 NSFileGroupOwnerAccountID=20 NSFileOwnerAccountName=kenshincui NSFileCreationDate=2014-07-28 11:47:58 +0000 NSFilePosixPermissions=420 NSFileHFSCreatorCode=0 NSFileType=NSFileTypeRegular NSFileExtendedAttributes={ "com.apple.TextEncoding" = <7574662d 383b3133 34323137 393834>; } NSFileGroupOwnerAccountName=staff NSFileReferenceCount=1 NSFileModificationDate=2014-07-28 11:47:58 +0000 */ //刪除文件 [manager removeItemAtPath:newPath error:nil]; } //文件操做--文件內容操做(NSData,非結構化字節流對象,有緩衝區管理機制,可用於網絡傳輸) void test3(){ NSFileManager *manager=[NSFileManager defaultManager]; NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt"; NSData *data=[manager contentsAtPath:filePath]; NSLog(@"%@",data);//存儲的是二進制字節流 //結果:<68656c6c 6f20776f 726c642c e4b896e7 958ce4bd a0e5a5bd efbc81> //NSData轉化成字符串 NSString *str1=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",str1); //結果:hello world,世界你好! //字符串轉化成NSData NSString *str2=@"Kenshin"; NSData *data2=[str2 dataUsingEncoding:NSUTF8StringEncoding]; NSLog(@"%@",data2); //固然通常若是僅僅是簡單讀取文件內容,直接用戶NSString方法便可 NSString *content=[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@",content); //結果:hello world,世界你好! } //文件操做--細粒度控制文件,文件操做柄 void test4(){ NSFileManager *manager=[NSFileManager defaultManager]; NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt"; //以只讀方式打開文件 NSFileHandle *fileHandle=[NSFileHandle fileHandleForReadingAtPath:filePath];//注意這個方法返回類型爲instancetype,也就是說對於上面的NSFileHandle它的返回類型也是NSFileHandle NSData *data= [fileHandle readDataToEndOfFile];//完整讀取文件 NSString *newPath=@"/Users/kenshincui/Desktop/test4.txt"; [manager createFileAtPath:newPath contents:nil attributes:nil]; NSFileHandle *fileHandle2=[NSFileHandle fileHandleForWritingAtPath:newPath];//以可寫方式打開文件 [fileHandle2 writeData:data];//寫入文件內容 [fileHandle2 closeFile];//關閉文件 //定位到指定位置,默認在文件開頭 [fileHandle seekToFileOffset:12]; NSData *data2= [fileHandle readDataToEndOfFile]; NSLog(@"data2=%@",[[NSString alloc]initWithData:data2 encoding:NSUTF8StringEncoding]); //結果:data2=世界你好! [fileHandle seekToFileOffset:6]; NSData *data3=[fileHandle readDataOfLength:5]; NSLog(@"data3=%@",[[NSString alloc]initWithData:data3 encoding:NSUTF8StringEncoding]); //結果:data3=world [fileHandle closeFile]; } //文件路徑 void test5(){ NSString *filePath=@"/Users/kenshincui/Desktop/myDocument"; NSString *filePath2=@"/Users/kenshincui/Desktop/test.txt"; //臨時文件所在目錄 NSString *path=NSTemporaryDirectory(); NSLog(@"temporary directory is :%@",path); //結果:/var/folders/h6/lss6gncs509c2pgzgty3wd_40000gn/T/ NSString *lastComponent= [filePath lastPathComponent]; NSLog(@"%@",lastComponent); //結果:myDocument NSLog(@"%@",[filePath stringByDeletingLastPathComponent]); //結果:/Users/kenshincui/Desktop NSLog(@"%@",[filePath stringByAppendingPathComponent:@"Pictrues"]); //結果:/Users/kenshincui/Desktop/myDocument/Pictrues NSLog(@"%@",[filePath2 pathExtension]); //結果:txt [[filePath pathComponents] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%i=%@",idx,obj); }]; /*結果: 0=/ 1=Users 2=kenshincui 3=Desktop 4=myDocument */ } //文件操做--NSURL void test6(){ NSURL *url=[NSURL URLWithString:@"http://developer.apple.com"]; NSString *str1=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@",str1); } //文件操做--NSBundle,程序包,通常用於獲取Resource中的資源(固然因爲當前並不是IOS應用沒有程序包,只是表示當前程序運行路徑) //在ios中常常用於讀取應用程序中的資源文件,如圖片、聲音、視頻等 void test7(){ //在程序包所在目錄建立一個文件 NSFileManager *manager=[NSFileManager defaultManager]; NSString *currentPath=[manager currentDirectoryPath]; NSLog(@"current path is :%@",currentPath); //結果:current path is :/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug NSString *filePath=[currentPath stringByAppendingPathComponent:@"test.txt"]; [manager createFileAtPath:filePath contents:[@"Hello,world!" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; //利用NSBundle在程序包所在目錄查找對應的文件 NSBundle *bundle=[NSBundle mainBundle];//主要操做程序包所在目錄 //若是有test.txt則返回路徑,不然返回nil NSString *path=[bundle pathForResource:@"test" ofType:@"txt"];//也能夠寫成:[bundle pathForResource:@"instructions.txt" ofType:nil]; NSLog(@"%@",path); //結果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug/test.txt NSLog(@"%@",[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]); //結果:Hello,world! //假設咱們在程序運行建立一個Resources目錄,而且其中新建pic.jpg,那麼用下面的方法得到這個文件完整路徑 NSString *path1= [bundle pathForResource:@"pic" ofType:@"jpg" inDirectory:@"Resources"]; NSLog(@"%@",path1); //結果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug/Resources/pic.jpg } int main(int argc,char *argv[]){ test1(); test2(); test3(); test4(); test5(); test6(); test7(); return 0; }
歸檔,在其餘語言中又叫「序列化」,就是將對象保存到硬盤;解檔,在其餘語言又叫「反序列化」就是將硬盤文件還原成對象。其實歸檔就是數據存儲的過程,在IOS中數據的存儲有五種方式:
xml屬性列表(plist歸檔)
NSUserDefaults(偏好設置)
NSKeyedArchiver歸檔(加密形式)
SQLite3(嵌入式數據庫)
Core Data(面向對象方式的嵌入式數據庫)
固然關於二、四、5點不是咱們今天介紹的重點,這個在IOS開發過程當中咱們會重點說到。
首先咱們先來看一下xml屬性列表,xml屬性列表進行歸檔的方式是將對象存儲在一個plist文件中,這個操做起來比較簡單,其實至關於xml序列化。可是同時它也有缺點:一是這種方式是明文保存的;二是這種方式操做的對象有限,只有NSArray、NSMutableArray、NSDictionary、NSMutableDictionary支持(歸檔時只要調用對應的writeToFile方法便可,解檔調用arrayWithContentsOfFile或dictionaryWithContentsOfFile,注意像NSString、NSNumber、NSData即便有這個方法它存儲的也不是xml格式)。
// // main.m // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <Foundation/Foundation.h> //xml屬性 void test1(){ //數組 NSString *path=@"/Users/kenshincui/Desktop/arrayXml.plist"; NSArray *array1=@[@"Kenshin",@"Kaoru",@"Rosa"]; [array1 writeToFile:path atomically:YES]; NSArray *array2=[NSArray arrayWithContentsOfFile:path]; [array2 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"array2[%lu]=%@",idx,obj); }]; /*結果: array1[0]=Kenshin array1[1]=Kaoru array1[2]=Rosa */ //字典 NSString *path2=@"/Users/kenshincui/Desktop/dicXml.plist"; NSDictionary *dic1=@{@"name":@"Kenshin",@"age":@28,@"height":@172.5}; [dic1 writeToFile:path2 atomically:YES]; NSDictionary *dic2=[NSDictionary dictionaryWithContentsOfFile:path2]; [dic2 enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { NSLog(@"dic2[%@]=%@",key,obj); }]; /*結果: dic2[height]=172.5 dic2[age]=28 dic2[name]=Kenshin */ } int main(int argc,char *argv[]){ test1(); return 0; }
生成的文件以下
若是要針對更多對象歸檔或者須要歸檔時可以加密的話就須要使用NSKeyedArchiver進行歸檔和解檔,使用這種方式歸檔的範圍更廣並且歸檔內容是密文存儲。從歸檔範圍來說NSKeyedArchiver適合全部ObjC對象,可是對於自定義對象咱們須要實現NSCoding協議;從歸檔方式來說NSKeyedArchiver分爲簡單歸檔和複雜對象歸檔,簡單歸檔就是針對單個對象能夠直接將對象做爲根對象(不用設置key),複雜對象就是針對多個對象,存儲時不一樣對象須要設置不一樣的Key。
首先看一下系統對象兩種歸檔方式(注意因爲本章主要介紹Foundation內容,下面的程序是OS X命令行程序並無建立成iOS應用,若是移植到到iOS應用下運行將NSArchiver和NSUnarchiver換成NSKeyedArchiver和NSKeyedUnarchiver。雖然在Foundation部分iOS和OS X在設計上儘量通用可是還存在着細微差異。)
// // 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歸檔 NSString *str1=@"Hello,world!"; NSString *path1=@"/Users/kenshincui/Desktop/archiver1.arc"; if(![NSArchiver archiveRootObject:str1 toFile:path1]){ NSLog(@"archiver failed!"); } //NSString解檔 NSString *str2= [NSUnarchiver unarchiveObjectWithFile:path1]; NSLog(@"str2=%@",str2);//結果:str2=Hello,world! //NSArray歸檔 NSString *path2=@"/Users/kenshincui/Desktop/archiver2.arc"; NSArray *array1=@[@"Kenshin",@"Kaoru",@"Rosa"]; if(![NSArchiver archiveRootObject:array1 toFile:path2]){ NSLog(@"archiver failed!"); } //NSArray解檔 NSArray *array2=[NSUnarchiver unarchiveObjectWithFile:path2]; [array2 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"array2[%lu]=%@",idx,obj); }]; /*結果: array2[0]=Kenshin array2[1]=Kaoru array2[2]=Rosa */ } //系統複雜對象歸檔(多對象歸檔) void test2(){ /*歸檔*/ NSString *path1=@"/Users/kenshincui/Desktop/archiver3.arc"; int int1=89; CGSize size1={12.5,16.8}; NSNumber *number1=@60.5; NSString *str1=@"Hello,world!"; NSArray *array1=@[@"Kenshin",@"Kaoru",@"Rosa"]; NSDictionary *dic1=@{@"name":@"Kenshin",@"age":@28,@"height":@172.5}; //同時對多個對象進行歸檔 NSMutableData *data1=[[NSMutableData alloc]init];//定義一個NSMutableData用於臨時存放數據 NSKeyedArchiver *archiver=[[NSKeyedArchiver alloc]initForWritingWithMutableData:data1];//定義歸檔對象 [archiver encodeInt:int1 forKey:@"int"];//對int1歸檔並指定一個key以便之後讀取 [archiver encodeSize:size1 forKey:@"size"]; [archiver encodeObject:number1 forKey:@"number"]; [archiver encodeObject:str1 forKey:@"string"]; [archiver encodeObject:array1 forKey:@"array"]; [archiver encodeObject:dic1 forKey:@"dic"]; [archiver finishEncoding];//結束歸檔 [data1 writeToFile:path1 atomically:YES];//寫入文件 /*解檔*/ int int2; CGSize size2; NSNumber *number2; NSString *str2; NSArray *array2; NSDictionary *dic2; NSData *data2=[[NSData alloc]initWithContentsOfFile:path1];//讀出數據到NSData NSKeyedUnarchiver *unarchiver=[[NSKeyedUnarchiver alloc]initForReadingWithData:data2]; int2= [unarchiver decodeInt64ForKey:@"int"]; size2=[unarchiver decodeSizeForKey:@"size"]; number2=[unarchiver decodeObjectForKey:@"number"]; str2=[unarchiver decodeObjectForKey:@"string"]; array2=[unarchiver decodeObjectForKey:@"array"]; dic2=[unarchiver decodeObjectForKey:@"dic"]; [unarchiver finishDecoding]; NSLog(@"int2=%i,size=%@,number2=%@,str2=%@,array2=%@,dic2=%@",int2,NSStringFromSize(size2),number2,str2,array2,dic2); /*結果: int2=89, size={12.5, 16.800000000000001}, number2=60.5, str2=Hello,world!, array2=( Kenshin, Kaoru, Rosa ), dic2={ age = 28; height = "172.5"; name = Kenshin; } */ } int main(int argc,char *argv[]){ test1(); test2(); return 0; }
接下來看一下自定義的對象如何歸檔,上面說了若是要對自定義對象進行歸檔那麼這個對象必須實現NSCoding協議,在這個協議中有兩個方法都必須實現:
-(void)encodeWithCoder:(NSCoder *)aCoder;經過給定的Archiver對消息接收者進行編碼;
-(id)initWithCoder:(NSCoder *)aDecoder;從一個給定的Unarchiver的數據返回一個初始化對象;
這兩個方法分別在歸檔和解檔時調用。下面經過一個例子進行演示(注意對於自定義類的多對象歸檔與系統類多對象歸檔徹底同樣,代碼中再也不演示):
Person.h
// // Person.h // FoundationFramework // // Created by Kenshin Cui on 14-2-16. // Copyright (c) 2014年 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 14-2-16. // Copyright (c) 2014年 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 14-2-16. // Copyright (c) 2014年 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; }今天的文章就到這裏了,內容確實很多,可是要用一篇文章把Foundation的全部內容說完也是徹底不現實的。這篇文章有一部份內容並無詳細的解釋代碼,這部份內容主要是我的認爲比較簡單,經過註釋你們就能夠理解。不過並非說這部份內容不重要,而是這些內容多數是記憶性的東西,不須要過多解釋。