国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

iOS開發(fā)系列—Objective-C之Foundation框架

2019-11-14 20:09:53
字體:
供稿:網(wǎng)友

概述

我們前面的章節(jié)中就一直新建Cocoa Class,那么Cocoa到底是什么,它和我們前面以及后面要講的內(nèi)容到底有什么關(guān)系呢?Objective-C開發(fā)中經(jīng)常用到NSObject,那么這個(gè)對象到底是誰?它為什么又出現(xiàn)在Objective-C中間呢?今天我們將揭開這層面紗,重點(diǎn)分析在IOS開發(fā)中一個(gè)重要的框架Foundation,今天的主要內(nèi)容有:

  1. Foundation概述
  2. 常用結(jié)構(gòu)體
  3. 日期
  4. 字符串
  5. 數(shù)組
  6. 字典
  7. 裝箱和拆箱
  8. 反射
  9. 拷貝
  10. 文件操作
  11. 歸檔

Foundation概述

為什么前面說的內(nèi)容中新建一個(gè)類的時(shí)候我們都是選擇Cocoa Class呢?Cocoa是什么呢?

Cocoa不是一種編程語言(它可以運(yùn)行多種編程語言),它也不是一個(gè)開發(fā)工具(通過命令行我們?nèi)匀豢梢蚤_發(fā)Cocoa程序),它是創(chuàng)建Mac OS X和IOS程序的原生面向?qū)ο驛PI,為這兩者應(yīng)用提供了編程環(huán)境。

我們通常稱為“Cocoa框架”,事實(shí)上Cocoa本身是一個(gè)框架的集合,它包含了眾多子框架,其中最重要的要數(shù)“Foundation”和“UIKit”。前者是框架的基礎(chǔ),和界面無關(guān),其中包含了大量常用的API;后者是基礎(chǔ)的UI類庫,以后我們在IOS開發(fā)中會經(jīng)常用到。這兩個(gè)框架在系統(tǒng)中的位置如下圖:

Cocoa

其實(shí)所有的Mac OS X和IOS程序都是由大量的對象構(gòu)成,而這些對象的根對象都是NSObject,NSObject就處在Foundation框架之中,具體的類結(jié)構(gòu)如下:

Foundation1

Foundation2

Foundation3

通常我們會將他們分為幾類:

  1. 值對象
  2. 集合
  3. 操作系統(tǒng)服務(wù):文件系統(tǒng)、URL、進(jìn)程通訊
  4. 通知
  5. 歸檔和序列化
  6. 表達(dá)式和條件判斷
  7. Objective-C語言服務(wù)

UIKit主要用于界面構(gòu)架,這里我們不妨也看一下它的類結(jié)構(gòu):

UIKit

常用結(jié)構(gòu)體

在Foundation中定義了很多常用結(jié)構(gòu)體類型來簡化我們的日常開發(fā),這些結(jié)構(gòu)體完全采用Objective-C定義,和我們自己定義的結(jié)構(gòu)體沒有任何區(qū)別,之所以由框架為我們提供完全是為了簡化我們的開發(fā)。常用的結(jié)構(gòu)體有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表示一個(gè)范圍*/void test1(){    NSRange rg={3,5};//第一參數(shù)是起始位置第二個(gè)參數(shù)是長度    //NSRange rg;    //rg.location=3;    //rg.length=5;    //NSRange rg={.location=3,.length=5};    //常用下面的方式定義 NSRange rg2=NSMakeRange(3,5);//使用NSMakeRange定義一個(gè)NSRange     //打印NSRange可以使用Foundation中方法 NSLog(@"rg2 is %@", NSStringFromRange(rg2));//注意不能直接NSLog(@"rg2 is %@", rg2),因?yàn)閞g2不是對象(準(zhǔn)確的說%@是指針)而是結(jié)構(gòu)體}/*NSPoint表示一個(gè)點(diǎn)*/void test2(){    NSPoint p=NSMakePoint(10, 15);//NSPoint其實(shí)就是CGPoint    //這種方式比較常見 NSPoint p2=CGPointMake(10, 15);    NSLog(NSStringFromPoint(p2));}/*NSSize表示大小*/void test3(){    NSSize s=NSMakeSize(10, 15);//NSSize其實(shí)就是CGSize    //這種方式比較常見 CGSize s2=CGSizeMake(10, 15);    NSLog(NSStringFromSize(s2));}/*NSRect表示一個(gè)矩形*/void test4(){    NSRect r=NSMakeRect(10, 5, 100, 200);//NSRect其實(shí)就是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;}
可以看到對于常用結(jié)構(gòu)體在Foundation框架中都有一個(gè)對應(yīng)的make方法進(jìn)行創(chuàng)建,這也是我們?nèi)蘸蟊容^常用的操作;而且與之對應(yīng)的還都有一個(gè)NSStringFromXX方法來進(jìn)行字符串轉(zhuǎn)換,方便我們調(diào)試。上面也提到NSSize其實(shí)就是CGSize,NSRect其實(shí)就是CGRect,我們可以通過查看代碼進(jìn)行確認(rèn),例如NSSize定義:

NSSize

繼續(xù)查看CGSize的代碼:

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];//獲得當(dāng)前日期    NSLog(@"%@",date1); //結(jié)果:2014-07-16 07:25:28 +0000        NSDate *date2=[NSDate dateWithTimeIntervalSinceNow:100];//在當(dāng)前日期的基礎(chǔ)上加上100秒,注意在ObjC中多數(shù)時(shí)間單位都是秒    NSLog(@"%@",date2); //結(jié)果:2014-07-16 07:27:08 +0000        NSDate *date3=[NSDate distantFuture];//隨機(jī)獲取一個(gè)將來的日期    NSLog(@"%@",date3); //結(jié)果:4001-01-01 00:00:00 +0000        NSTimeInterval time=[date2 timeIntervalSinceDate:date1];//日期之差,返回單位為秒    NSLog(@"%f",time); //結(jié)果:100.008833        NSDate *date5=[date1 earlierDate:date3];//返回比較早的日期    NSLog(@"%@",date5); //結(jié)果: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); //結(jié)果:14-07-16 15:25:28    //字符串轉(zhuǎn)化為日期    NSDate *date6=[formater1 dateFromString:@"14-02-14 11:07:16"];    NSLog(@"%@",date6); //結(jié)果:2014-02-14 03:07:16 +0000    return 0;}

字符串

不可變字符串

在ObjC中字符串操作要比在C語言中簡單的多,在下面的例子中你將看到字符串的初始化、大小寫轉(zhuǎn)化、后綴前綴判斷、字符串比較、字符串截取、字符串轉(zhuǎn)換等,通過下面的例子我們基本可以掌握常用的字符串操作(注意這些內(nèi)容雖然基本,但卻是十分常用的操作,需要牢記):

////  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語言創(chuàng)建的字符串    NSString *str2=@"OC string";//ObjC字符串需要加@,并且這種方式創(chuàng)建的對象不需要自己釋放內(nèi)存    //下面的創(chuàng)建方法都應(yīng)該釋放內(nèi)存    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語言的字符串轉(zhuǎn)換為ObjC字符串    //以上方法都有對應(yīng)靜態(tài)方法(一般以string開頭),不需要管理內(nèi)存(系統(tǒng)靜態(tài)方法一般都是自動釋放)    NSString *str7=[NSString stringWithString:@"Objective-C string"];}void test2(){    NSLog(@"/"Hello world!/" to upper is %@",[@"Hello world!" uppercaseString]);    //結(jié)果:"Hello world!" to upper is HELLO WORLD!    NSLog(@"/"Hello world!/" to lowwer is %@",[@"Hello world!" lowercaseString]);    //結(jié)果:"Hello world!" to lowwer is hello world!         //首字母大寫,其他字母小寫    NSLog(@"/"Hello world!/" to capitalize is %@",[@"Hello world!" capitalizedString]);    //結(jié)果:"Hello world!" to capitalize is Hello World!         BOOL result= [@"abc" isEqualToString:@"aBc"];    NSLog(@"%i",result);    //結(jié)果: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.");    }    //結(jié)果:left>right.}void test3(){    NSLog(@"has PRefix ab? %i",[@"abcdef" hasprefix:@"ab"]);    //結(jié)果:has prefix ab? 1    NSLog(@"has suffix ab? %i",[@"abcdef" hasSuffix:@"ef"]);    //結(jié)果:has suffix ab? 1    NSRange range=[@"abcdefabcdef" rangeOfString:@"cde"];//注意如果遇到cde則不再往后面搜索,如果從后面搜索或其他搜索方式可以設(shè)置第二個(gè)options參數(shù)    if(range.location==NSNotFound){        NSLog(@"not found.");    }else{        NSLog(@"range is %@",NSStringFromRange(range));    }    //結(jié)果:range is {2, 3}}//字符串分割void test4(){    NSLog(@"%@",[@"abcdef" substringFromIndex:3]);//從第三個(gè)索引開始(包括第三個(gè)索引對應(yīng)的字符)截取到最后一位    //結(jié)果:def    NSLog(@"%@",[@"abcdef" substringToIndex:3]);////從0開始截取到第三個(gè)索引(不包括第三個(gè)索引對應(yīng)的字符)    //結(jié)果:abc    NSLog(@"%@",[@"abcdef" substringWithRange:NSMakeRange(2, 3)]);    //結(jié)果:cde    NSString *str1=@"12.abcd.3a";    NSArray *array1=[str1 componentsSeparatedByString:@"."];//字符串分割    NSLog(@"%@",array1);     /*結(jié)果:      (         12,         abcd,         3a      )      */ }//其他操作void test5(){    NSLog(@"%i",[@"12" intValue]);//類型轉(zhuǎn)換    //結(jié)果:12    NSLog(@"%zi",[@"hello world,世界你好!" length]);//字符串長度注意不是字節(jié)數(shù)    //結(jié)果:17    NSLog(@"%c",[@"abc" characterAtIndex:0]);//取出制定位置的字符    //結(jié)果:a    const char *s=[@"abc" UTF8String];//轉(zhuǎn)換為C語言字符串    NSLog(@"%s",s);    //結(jié)果:abc}int main(int argc, const char * argv[]) {    test1();    test2();    test3();    test4();    test5();    return 0;}

注意:上面代碼注釋中提到的需要釋放內(nèi)存指的是在MRC下的情況,當(dāng)然本質(zhì)上在ARC下也需要釋放,只是這部分代碼編譯器會自動創(chuàng)建。

擴(kuò)展--文件操作

在ObjC中路徑、文件讀寫等操作是利用字符串來完成的,這里通過幾個(gè)簡單的例子來演示(首先在桌面上新建一個(gè)test.txt文件,里面存儲的內(nèi)容是”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(){    //讀取文件內(nèi)容    NSString *path=@"/Users/kenshincui/Desktop/test.txt";    NSString *str1=[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];    //注意上面也可以使用gb2312 gbk等,例如kCFStringEncodingGB_18030_2000,但是需要用CFStringConvertEncodingToNSStringEncoding轉(zhuǎn)換    NSLog(@"str1 is %@",str1);    //結(jié)果:str1 is hello world,世界你好!                //上面我們看到了讀取文件,但并沒有處理錯(cuò)誤,當(dāng)然在ObjC中可以@try @catch @finnally但通常我們并不那么做    //由于我們的test.txt中有中文,所以使用下面的編碼讀取會報(bào)錯(cuò),下面的代碼演示了錯(cuò)誤獲取的過程    NSError *error;    NSString *str2=[NSString stringWithContentsOfFile:path encoding:kCFStringEncodingGB_18030_2000 error:&error];//注意這句話中的error變量是**error,就是指針的指針那就是指針的地址,由于error就是一個(gè)指針此處也就是error的地址&error,具體原因見下面補(bǔ)充    if(error){        NSLog(@"read error ,the error is %@",error);    }else{        NSLog(@"read success,the file content is %@",str2);    }    //結(jié)果: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}                //讀取文件內(nèi)容還有一種方式就是利用URl,它除了可以讀取本地文件還可以讀取網(wǎng)絡(luò)文件    //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代表一次性寫入,如果寫到中間出錯(cuò)了最后就全部不寫入    if(error1){        NSLog(@"write fail,the error is %@",[error1 localizedDescription]);//調(diào)用localizedDescription是只打印關(guān)鍵錯(cuò)誤信息    }else{        NSLog(@"write success!");    }    //結(jié)果:write success!}//路徑操作void test3(){    NSMutableArray *marray=[NSMutableArray array];//可變數(shù)組    [marray addObject:@"Users"];    [marray addObject:@"KenshinCui"];    [marray addObject:@"Desktop"];    NSString *path=[NSString pathWithComponents:marray];    NSLog(@"%@",path);//字符串拼接成路徑    //結(jié)果:Users/KenshinCui/Desktop    NSLog(@"%@",[path pathComponents]);//路徑分割成數(shù)組    /*結(jié)果:      (        Users,        KenshinCui,        Desktop    )    */    NSLog(@"%i",[path isAbsolutePath]);//是否絕對路徑(其實(shí)就是看字符串是否以“/”開頭)    //結(jié)果:0    NSLog(@"%@",[path lastPathComponent]);//取得最后一個(gè)目錄    //結(jié)果:Desktop    NSLog(@"%@",[path stringByDeletingLastPathComponent]);//刪除最后一個(gè)目錄,注意path本身是常量不會被修改,只是返回一個(gè)新字符串    //結(jié)果:Users/KenshinCui    NSLog(@"%@",[path stringByAppendingPathComponent:@"Documents"]);//路徑拼接    //結(jié)果:Users/KenshinCui/Desktop/Documents} //擴(kuò)展名操作void test4(){    NSString *path=@"Users/KenshinCui/Desktop/test.txt";    NSLog(@"%@",[path pathExtension]);//取得擴(kuò)展名,注意ObjC中擴(kuò)展名不包括"."    //結(jié)果:txt    NSLog(@"%@",[path stringByDeletingPathExtension]);//刪除擴(kuò)展名,注意包含"."    //結(jié)果:Users/KenshinCui/Desktop/test    NSLog(@"%@",[@"Users/KenshinCui/Desktop/test" stringByAppendingPathExtension:@"mp3"]);//添加擴(kuò)展名    //結(jié)果:Users/KenshinCui/Desktop/test.mp3}int main(int argc, const char * argv[]) {    test1();    test2();    test3();    test4();    return 0;}

注意:在上面的例子中我們用到了可變數(shù)組,下面會專門介紹。

可變字符串

我們知道在字符串操作過程中我們經(jīng)常希望改變原來的字符串,當(dāng)然這在C語言中實(shí)現(xiàn)比較復(fù)雜,但是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"];//設(shè)置字符串    NSLog(@"%@",str1);    //結(jié)果:hello    [str1 appendString:@",world!"];//追加字符串    NSLog(@"%@",str1);    //結(jié)果:hello,world!    [str1 appendFormat:@"我的年齡是%i。dear,I love you.",18];    NSLog(@"%@",str1);    //結(jié)果:hello,world!我的年齡是18。dear,I love you.        //替換字符串    NSRange range=[str1 rangeOfString:@"dear"];    [str1 replaceCharactersInRange:range withString:@"Honey"];    NSLog(@"%@",str1);    //結(jié)果:hello,world!我的年齡是18。Honey,I love you.        //插入字符串    [str1 insertString:@"My name is Kenshin." atIndex:12];    NSLog(@"%@",str1);    //結(jié)果:hello,world!My name is Kenshin.我的年齡是18。Honey,I love you.        //刪除指定字符串    [str1 deleteCharactersInRange:[str1 rangeOfString:@"My name is Kenshin."]];//刪除指定范圍的字符串    NSLog(@"%@",str1);    //結(jié)果:hello,world!我的年齡是18。Honey,I love you.        return 0;}

數(shù)組

不可變數(shù)組

下面將演示常用的數(shù)組操作:初始化、數(shù)組對象的方法執(zhí)行、數(shù)組元素的遍歷、在原有數(shù)組基礎(chǔ)上產(chǎn)生新數(shù)組、數(shù)組排序等

////  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長度不可變所以初始化的時(shí)候就賦值,并且最后以nil結(jié)尾    //此外需要注意NSArray不能存放C語言的基礎(chǔ)類型    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);//數(shù)組長度,結(jié)果:5    NSLog(@"%i",[array1 containsObject:@"cde"]);//是否包含某個(gè)對象,結(jié)果:1    NSLog(@"%@",[array1 lastObject]);//最后一個(gè)對象,結(jié)果: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!"];//執(zhí)行所有元素的showMessage方法,后面的參數(shù)最多只能有一個(gè)    /*結(jié)果:     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!".     */}//數(shù)組的遍歷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]);    }    /*結(jié)果:     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);    }    /*結(jié)果:     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){//當(dāng)idx=2時(shí)設(shè)置*stop為YES停止遍歷            *stop=YES;        }    }];    /*結(jié)果:     method3:index 0 is abc     method3:index 1 is <NSObject: 0x100106de0>     method3:index 2 is cde     */            //方法4,利用迭代器    //NSEnumerator *enumerator= [array objectEnumerator];//獲得一個(gè)迭代器    NSEnumerator *enumerator=[array reverSEObjectEnumerator];//獲取一個(gè)反向迭代器    //NSLog(@"all:%@",[enumerator allObjects]);//獲取所有迭代對象,注意調(diào)用完此方法迭代器就遍歷完了,下面的nextObject就沒有值了    id obj2=nil;    while (obj2=[enumerator nextObject]) {        NSLog(@"method4:%@",obj2);    }    /*結(jié)果:     method4:25     method4:opq     method4:cde     method4:<NSObject: 0x100106de0>     method4:abc     */}//數(shù)組派生出新的數(shù)組void test3(){    NSArray *array=[NSArray arrayWithObjects:@"1",@"2",@"3", nil];    NSArray *array2=[array arrayByAddingObject:@"4"];//注意此時(shí)array并沒有變    NSLog(@"%@",array2);    /*結(jié)果:     (         1,         2,         3,         4     )     */            NSLog(@"%@",[array2 arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:@"5",@"6", nil]]);//追加形成新的數(shù)組    /*結(jié)果:     (         1,         2,         3,         4,         5,         6     )     */            NSLog(@"%@",[array2 subarrayWithRange:NSMakeRange(1, 3)]);//根據(jù)一定范圍取得生成一個(gè)新的數(shù)組    /*結(jié)果:     (         2,         3,         4     )     */            NSLog(@"%@",[array componentsJoinedByString:@","]);//數(shù)組連接,形成一個(gè)字符串    //結(jié)果:1,2,3        //讀寫文件    NSString *path=@"/Users/KenshinCui/Desktop/array.xml";    [array writeToFile:path atomically:YES];    NSArray *array3=[NSArray arrayWithContentsOfFile:path];    NSLog(@"%@",array3);    /*結(jié)果:     (         1,         2,         3     )     */}//數(shù)組排序void test4(){    //方法1,使用自帶的比較器    NSArray *array=[NSArray arrayWithObjects:@"3",@"1",@"2", nil];    NSArray *array2= [array sortedArrayUsingSelector:@selector(compare:)];    NSLog(@"%@",array2);    /*結(jié)果:     (         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);    /*結(jié)果:     (         "name=Kaoru",         "name=Kenshin",         "name=Rosa"     )     */            //方法3使用代碼塊    NSArray *array5=[array3 sortedArrayUsingComparator:^NSComparisonResult(Person *obj1, Person *obj2) {        return [obj2.name compare:obj1.name];//降序    }];    NSLog(@"%@",array5);    /*結(jié)果:     (         "name=Rosa",         "name=Kenshin",         "name=Kaoru"     )     */            //方法4 通過描述器定義排序規(guī)則    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];    //定義一個(gè)排序描述    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);    /*結(jié)果:     (         "name=Jack",         "name=Jerry",         "name=Terry",         "name=Tom"     )     */}int main(int argc, const char * argv[]) {    test1();    test2();    test3();    test4();    return 0;}

需要注意幾點(diǎn):

  • NSArray中只能存放對象,不能存放基本數(shù)據(jù)類型,通常我們可以通過在基本數(shù)據(jù)類型前加@進(jìn)行轉(zhuǎn)換;
  • 數(shù)組中的元素后面必須加nil以表示數(shù)據(jù)結(jié)束;
  • makeObjectsPerformSelector執(zhí)行數(shù)組中對象的方法,其參數(shù)最多只能有一個(gè);
  • 上面數(shù)組操作中無論是數(shù)組的追加、刪除、截取都沒有改變原來的數(shù)組,只是產(chǎn)生了新的數(shù)組而已;
  • 對象的比較除了使用系統(tǒng)自帶的方法,我們可以通過自定義比較器的方法來實(shí)現(xiàn);

可變數(shù)組

下面看一下可變數(shù)組的內(nèi)容:

////  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);    /*結(jié)果:     (         "name=Kenshin",         "name=Kaoru",         "name=Rosa"     )     */        Person *person4=[Person personWithName:@"Jack"];//此時(shí)person4的retainCount為1    [array1 addObject:person4];//添加一個(gè)元素,此時(shí)person4的retainCount為2    NSLog(@"%@",array1);    /*結(jié)果:     (         "name=Kenshin",         "name=Kaoru",         "name=Rosa",         "name=Jack"     )     */        [array1 removeObject:person3];//刪除一個(gè)元素    NSLog(@"%@",array1);    /*結(jié)果:     (         "name=Kenshin",         "name=Kaoru",         "name=Jack"     )     */        [array1 removeLastObject];//刪除最后一個(gè)元素,//此時(shí)person4的retainCount為1    NSLog(@"%@",array1);    /*結(jié)果:     (         "name=Kenshin",         "name=Kaoru"     )     */        [array1 removeAllObjects];//刪除所以元素        //注意當(dāng)往數(shù)組中添加一個(gè)元素時(shí)會retain因此計(jì)數(shù)器+1,當(dāng)從數(shù)組中移除一個(gè)元素時(shí)會release因此計(jì)數(shù)器-1    //當(dāng)NSMutalbeArray對象release的時(shí)候會依次調(diào)用每一個(gè)對象的release}void test2(){    NSMutableArray *array1=[NSMutableArray arrayWithObjects:@"1",@"3",@"2", nil];    NSLog(@"%@",array1);    /*結(jié)果:     (         1,         3,         2     )     */        NSArray *array2= [array1 sortedArrayUsingSelector:@selector(compare:)];//注意這個(gè)方法沒有修改array1    NSLog(@"%@",array1);    /*結(jié)果:     (         1,         3,         2     )     */        NSLog(@"%@",array2);    /*結(jié)果:     (         1,         2,         3     )     */    [array1 sortUsingSelector:@selector(compare:)];//這個(gè)方法會修改array1    NSLog(@"%@",array1);    /*結(jié)果:     (         1,         2,         3     )     */    }int main(int argc, const char * argv[]) {        test1();        test2();        return 0;}
  • 可變數(shù)組中的元素后面必須加nil以表示數(shù)據(jù)結(jié)束;
  • 往一個(gè)可變數(shù)組中添加一個(gè)對象,此時(shí)這個(gè)對象的引用計(jì)數(shù)器會加1,當(dāng)這個(gè)對象從可變數(shù)組中移除其引用計(jì)數(shù)器減1。同時(shí)當(dāng)整個(gè)數(shù)組銷毀之后會依次調(diào)用每個(gè)對象的releaes方法。
  • 在不可變數(shù)組中無論對數(shù)組怎么排序,原來的數(shù)組順序都不會改變,但是在可變數(shù)組中如果使用sortUsingSelector:排序原來的數(shù)組順序就發(fā)生了變化。

 

字典

字典在我們?nèi)粘i_發(fā)中也是比較常用的,通過下面的代碼我們看一下在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);    /*結(jié)果:     {        a = 1;     }     */        //常用的方式    NSDictionary *dic2=[NSDictionary dictionaryWithObjectsAndKeys:                        @"1",@"a",                        @"2",@"b",                        @"3",@"c",                        nil];    NSLog(@"%@",dic2);    /*結(jié)果:     {         a = 1;         b = 2;         c = 3;     }     */            NSDictionary *dic3=[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1",@"2", nil] forKeys:[NSArray arrayWithObjects:@"a",@"b", nil]];    NSLog(@"%@",dic3);    /*結(jié)果:     {         a = 1;         b = 2;     }     */            //更簡單的方式    NSDictionary *dic4=@{@"1":@"a",@"2":@"b",@"3":@"c"};    NSLog(@"%@",dic4);    /*結(jié)果:     {         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]); //結(jié)果:4    NSLog(@"%@",[dic1 valueForKey:@"b"]);//根據(jù)鍵取得值,結(jié)果:2    NSLog(@"%@",dic1[@"b"]);//還可以這樣讀取,結(jié)果:2    NSLog(@"%@,%@",[dic1 allKeys],[dic1 allValues]);    /*結(jié)果:     (         d,         b,         c,         a     ),(         2,         2,         3,         1     )     */        NSLog(@"%@",[dic1 objectsForKeys:[NSArray arrayWithObjects:@"a",@"e" , nil]notFoundMarker:@"not fount"]);//后面一個(gè)參數(shù)notFoundMarker是如果找不到對應(yīng)的key用什么值代替    /*結(jié)果:     (         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遍歷循環(huán)的是key        NSLog(@"%@=%@",key,[dic1 objectForKey:key]);    }    /*結(jié)果:     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]);            }    /*結(jié)果:     d=2     b=2     c=3     a=1     */        //遍歷3    [dic1 enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {        NSLog(@"%@=%@",key,obj);    }];    /*結(jié)果:     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);    /*結(jié)果:     {         a = 1;         c = 3;         d = 2;     }     */        [dic addEntriesFromDictionary:@{@"e":@"7",@"f":@"6"}];    NSLog(@"%@",dic);    /*結(jié)果:     {         a = 1;         c = 3;         d = 2;         e = 7;         f = 6;     }     */        [dic setValue:@"5" forKey:@"a"];    NSLog(@"%@",dic);    /*結(jié)果:     {         a = 5;         c = 3;         d = 2;         e = 7;         f = 6;     }     */             //注意,一個(gè)字典的key或value添加到字典中時(shí)計(jì)數(shù)器+1;字典釋放時(shí)調(diào)用key或value的release一次,計(jì)數(shù)器-1}int main(int argc, const char * argv[]) {    test1();    test2();    test3();    test4();    return 0;}

注意:同數(shù)組一樣,不管是可變字典還是不可變字典初始化元素后面必須加上nil以表示結(jié)束。

裝箱和拆箱

其實(shí)從上面的例子中我們也可以看到,數(shù)組和字典中只能存儲對象類型,其他基本類型和結(jié)構(gòu)體是沒有辦法放到數(shù)組和字典中的,當(dāng)然你也是無法給它們發(fā)送消息的(也就是說有些NSObject的方法是無法調(diào)用的),這個(gè)時(shí)候通常會用到裝箱(boxing)和拆箱(unboxing)。其實(shí)各種高級語言基本上都有裝箱和拆箱的過程,例如C#中我們將基本數(shù)據(jù)類型轉(zhuǎn)化為Object就是一個(gè)裝箱的過程,將這個(gè)Object對象轉(zhuǎn)換為基本數(shù)據(jù)類型的過程就是拆箱,而且在C#中裝箱的過程可以自動完成,基本數(shù)據(jù)類型可以直接賦值給Object對象。但是在ObjC中裝箱的過程必須手動實(shí)現(xiàn),ObjC不支持自動裝箱。

在ObjC中我們一般將基本數(shù)據(jù)類型裝箱成NSNumber類型(當(dāng)然它也是NSObject的子類,但是NSNumber不能對結(jié)構(gòu)體裝箱),調(diào)用其對應(yīng)的方法進(jìn)行轉(zhuǎn)換:

+(NSNumber *)numberWithChar:(char)value;

+(NSNumber *)numberWithInt:(int)value;

+(NSNumber *)numberWithFloat:(float)value;

+(NSNumber *)numberWithDouble:(double)value;

+(NSNumber *)numberWithBool:(BOOL)value;

+(NSNumber *)numberWithInteger:(NSInteger)value;

拆箱的過程就更加簡單了,可以調(diào)用如下方法:

-(char)charValue;

-(int)intValue;

-(float)floatValue;

-(double)doubleValue;

-(BOOL)boolValue;

簡單看一個(gè)例子

////  main.m//  FoundationFramework////  Created by Kenshin Cui on 14-2-16.//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import <Foundation/Foundation.h>/*可以存放基本類型到數(shù)組、字典*/void test1(){    //包裝類NSNumber,可以包裝基本類型但是無法包裝結(jié)構(gòu)體類型    NSNumber *number1=[NSNumber numberWithChar:'a'];//'a'是一個(gè)C語言的char類型我們無法放倒NSArray中,但是我們可以通過NSNumber包裝    NSArray *array1=[NSArray arrayWithObject:number1];    NSLog(@"%@",array1);    /*結(jié)果:     (        97     )     */        NSNumber *number2= [array1 lastObject];    NSLog(@"%@",number2);//返回的不是基本類型,結(jié)果:97            char char1=[number2 charValue];//number轉(zhuǎn)化為char    NSLog(@"%c",char1); //結(jié)果:a}int main(int argc, const char * argv[]) {    test1();    return  0;}

上面我們看到了基本數(shù)據(jù)類型的裝箱和拆箱過程,那么結(jié)構(gòu)體呢?這個(gè)時(shí)候我們需要引入另外一個(gè)類型NSValue,其實(shí)上面的NSNumber就是NSValue的子類,它包裝了一些基本數(shù)據(jù)類型的常用裝箱、拆箱方法,當(dāng)要對結(jié)構(gòu)體進(jìn)行裝箱、拆箱操作我們需要使用NSValue,NSValue可以對任何數(shù)據(jù)類型進(jìn)行裝箱、拆箱操作。

事實(shí)上對于常用的結(jié)構(gòu)體Foundation已經(jīng)為我們提供好了具體的裝箱方法:

+(NSValue *)valueWithPoint:(NSPoint)point;

+(NSValue *)valueWithSize:(NSSize)size;

+(NSValue *)valueWithRect:(NSRect)rect;

對應(yīng)的拆箱方法:

-(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可以包裝任何類型,包括結(jié)構(gòu)體void test1(){    CGPoint point1=CGPointMake(10, 20);    NSValue *value1=[NSValue valueWithPoint:point1];//對于系統(tǒng)自帶類型一般都有直接的方法進(jìn)行包裝    NSArray *array1=[NSArray arrayWithObject:value1];//放倒數(shù)組中    NSLog(@"%@",array1);    /*結(jié)果:     (        "NSPoint: {10, 20}"     )     */        NSValue *value2=[array1 lastObject];    CGPoint point2=[value2 pointValue];//同樣對于系統(tǒng)自帶的結(jié)構(gòu)體有對應(yīng)的取值方法(例如本例pointValue)    NSLog(@"x=%f,y=%f",point2.x,point2.y);//結(jié)果:x=10.000000,y=20.000000}int main(int argc, const char * argv[]) {    test1();    return  0;}

 

那么如果是我們自定義的結(jié)構(gòu)體類型呢,這個(gè)時(shí)候我們需要使用NSValue如下方法進(jìn)行裝箱:

+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;

調(diào)用下面的方法進(jìn)行拆箱:

-(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可以包裝任何類型,包括結(jié)構(gòu)體void test1(){    //如果我們自己定義的結(jié)構(gòu)體包裝    Date date={2014,2,28};    char *type=@encode(Date);    NSValue *value3=[NSValue value:&date withObjCType:type];//第一參數(shù)傳遞結(jié)構(gòu)體地址,第二個(gè)參數(shù)傳遞類型字符串    NSArray *array2=[NSArray arrayWithObject:value3];    NSLog(@"%@",array2);    /*結(jié)果:     (        "<de070000 02000000 1c000000>"     )     */        Date date2;    [value3 getValue:&date2];//取出對應(yīng)的結(jié)構(gòu)體,注意沒有返回值    //[value3 objCType]//取出包裝內(nèi)容的類型    NSLog(@"%i,%i,%i",date2.year,date2.month,date2.day); //結(jié)果:2014,2,28    }int main(int argc, const char * argv[]) {    test1();    return  0;}

擴(kuò)展1-NSNull

通過前面的介紹大家都知道無論在數(shù)組還是在字典中都必須以nil結(jié)尾,否則數(shù)組或字典無法判斷是否這個(gè)數(shù)組或字典已經(jīng)結(jié)束(與C語言中的字符串比較類似,C語言中定義字符串后面必須加一個(gè)”/0”)。但是我們有時(shí)候確實(shí)想在數(shù)據(jù)或字典中存儲nil值而不是作為結(jié)束標(biāo)記怎么辦呢?這個(gè)時(shí)候需要使用NSNull,這個(gè)類是一個(gè)單例,只有一個(gè)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];//注意這是一個(gè)對象,是一個(gè)單例,只有一個(gè)方法null創(chuàng)建一個(gè)對象    NSNull *nl2=[NSNull null];    NSLog(@"%i",nl==nl2);//由于是單例所以地址相等,結(jié)果:1        NSArray *array1=[NSArray arrayWithObjects:@"abc",nl,@123, nil];    NSLog(@"%@",array1);    /*結(jié)果:     (         abc,         "<null>",         123     )     */    return  0;}

 

擴(kuò)展2-@符號

我們知道在ObjC中很多關(guān)鍵字前都必須加上@符號,例如@protocol、@property等,當(dāng)然ObjC中的字符串必須使用@符號,還有就是%@可以表示輸出一個(gè)對象。其實(shí)@符號在新版的ObjC中還有一個(gè)作用:裝箱。

相信聰明的童鞋在前面的例子中已經(jīng)看到了,這里簡單的介紹一下(在下面的演示中你也將看到很多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);    /*結(jié)果:     (         100,         abc,         16,         65,         "16.7"         1     )     */    NSNumber *number2=@(1+2*3);    NSLog(@"%@",number2); //結(jié)果:7    NSNumber *number3=@(autumn);    NSLog(@"%@",number3); //結(jié)果:2        NSArray *array2=@[@"abc",@16,@'A',@16.7,@YES];//使用這種方式最后不用添加nil值了    NSLog(@"%@",array2[2]); //結(jié)果:65    NSMutableArray *array3=[NSMutableArray arrayWithArray:array2];    array3[0]=@"def";    NSLog(@"%@",array3[0]); //結(jié)果:def        NSDictionary *dic1=@{@"a":@123,@"b":@'c',@"c":@YES};    NSLog(@"%@",dic1);    /*結(jié)果:     {         a = 123;         b = 99;         c = 1;     }     */    NSMutableDictionary *dic2=[NSMutableDictionary dictionaryWithDictionary:dic1];    dic2[@"a"]=@456;    NSLog(@"%@",dic2[@"a"]);//結(jié)果:456    return 0;}

反射

由于ObjC動態(tài)性,在ObjC中實(shí)現(xiàn)反射可以說是相當(dāng)簡單,下面代碼中演示了常用的反射操作,具體作用也都在代碼中進(jìn)行了注釋說明:

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;//自己實(shí)現(xiàn)對象比較方法-(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);}//自己實(shí)現(xiàn)對象比較方法-(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]]); //判斷一個(gè)對象是否為某種類型(如果是父類也返回YES),結(jié)果:1    NSLog(@"%i",[person1 isMemberOfClass:[NSObject class]]); //判斷一個(gè)對象是否是某個(gè)類的實(shí)例化對象,結(jié)果:0    NSLog(@"%i",[person1 isMemberOfClass:[Person class]]); //結(jié)果:1    NSLog(@"%i",[person1 conformsToProtocol:@protocol(NSCopying)]);//是否實(shí)現(xiàn)了某個(gè)協(xié)議,結(jié)果:0    NSLog(@"%i",[person1 respondsToSelector:@selector(showMessage:)]);//是否存在某個(gè)方法,結(jié)果:1        [person1 showMessage:@"Hello,world!"];//直接調(diào)用一個(gè)方法    [person1 performSelector:@selector(showMessage:) withObject:@"Hello,world!"];    //動態(tài)調(diào)用一個(gè)方法,注意如果有參數(shù)那么參數(shù)類型只能為ObjC對象,并且最多只能有兩個(gè)參數(shù)        /*反射*/    //動態(tài)生成一個(gè)類    NSString *className=@"Person";    Class myClass=NSClassFromString(className);//根據(jù)類名生成類    Person *person2=[[myClass alloc]init]; //實(shí)例化    person2.name=@"Kaoru";    NSLog(@"%@",person2);//結(jié)果:name=Kaoru    //類轉(zhuǎn)化為字符串    NSLog(@"%@,%@",NSStringFromClass(myClass),NSStringFromClass([Person class])); //結(jié)果:Person,Person    //調(diào)用方法    NSString *methodName=@"showMessage:";    SEL mySelector=NSSelectorFromString(methodName);    Person *person3=[[myClass alloc]init];    person3.name=@"Rosa";    [person3 performSelector:mySelector withObject:@"Hello,world!"]; //結(jié)果:My name is Rosa,the infomation is "Hello,world!".    //方法轉(zhuǎn)化為字符串    NSLog(@"%@",NSStringFromSelector(mySelector)); //結(jié)果:showMessage:        return 0;}

拷貝

對象拷貝操作也比較常見,在ObjC中有兩種方式的拷貝:copy和mutablecopy,這兩種方式都將產(chǎn)生一個(gè)新的對象,只是后者產(chǎn)生的是一個(gè)可變對象。在ObjC中如果要想實(shí)現(xiàn)copy或者mutablecopy操作需要實(shí)現(xiàn)NSCopy或者NSMutableCopy協(xié)議,拷貝操作產(chǎn)生的新的對象默認(rèn)引用計(jì)數(shù)器是1,在非ARC模式下我們應(yīng)該對這個(gè)對象進(jìn)行內(nèi)存管理。在熟悉這兩種操作之前我們首先需要弄清兩個(gè)概念:深復(fù)制(或深拷貝)和淺復(fù)制(或淺拷貝)。

  • 淺復(fù)制:在執(zhí)行復(fù)制操作時(shí),對于對象中每一層(對象中包含的對象,例如說屬性是某個(gè)對象類型)復(fù)制都是指針復(fù)制(如果從引用計(jì)數(shù)器角度出發(fā),那么每層對象的引用計(jì)數(shù)器都會加1)。
  • 深復(fù)制:在執(zhí)行復(fù)制操作時(shí),至少有一個(gè)對象的復(fù)制是對象內(nèi)容復(fù)制(如果從引用計(jì)數(shù)器角度出發(fā),那么除了對象內(nèi)容復(fù)制的那個(gè)對象的引用計(jì)數(shù)器不變,其他指針復(fù)制的對象其引用計(jì)數(shù)器都會加1)。

注:

指針拷貝:拷貝的是指針本身(也就是具體對象的地址)而不是指向的對象內(nèi)容本身。

對象復(fù)制:對象復(fù)制指的是復(fù)制內(nèi)容是對象本身而不是對象的地址。

完全復(fù)制:上面說了深復(fù)制和淺復(fù)制,既然深復(fù)制是至少一個(gè)對象復(fù)制是對象內(nèi)容復(fù)制,那么如果所有復(fù)制都是對象內(nèi)容復(fù)制那么這個(gè)復(fù)制就叫完全復(fù)制。

對比copy和mutablecopy其實(shí)前面我們一直還用到一個(gè)操作是retain,它們之間的關(guān)系如下:

retain:始終采取淺復(fù)制,引用計(jì)數(shù)器會加1,返回的對象和被復(fù)制對象是同一個(gè)對象1(也就是說這個(gè)對象的引用多了一個(gè),或者說是指向這個(gè)對象的指針多了一個(gè));

copy:對于不可變對象copy采用的是淺復(fù)制,引用計(jì)數(shù)器加1(其實(shí)這是編譯器進(jìn)行了優(yōu)化,既然原來的對象不可變,復(fù)制之后的對象也不可變那么就沒有必要再重新創(chuàng)建一個(gè)對象了);對于可變對象copy采用的是深復(fù)制,引用計(jì)數(shù)器不變(原來的對象是可變,現(xiàn)在要產(chǎn)生一個(gè)不可變的當(dāng)然得重新產(chǎn)生一個(gè)對象);

mutablecopy:無論是可變對象還是不可變對象采取的都是深復(fù)制,引用計(jì)數(shù)器不變(如果從一個(gè)不可變對象產(chǎn)生一個(gè)可變對象自然不用說兩個(gè)對象絕對不一樣肯定是深復(fù)制;如果從一個(gè)可變對象產(chǎn)生出另一個(gè)可變對象,那么當(dāng)其中一個(gè)對象改變自然不希望另一個(gè)對象改變,當(dāng)然也是深復(fù)制)。

注:

可變對象:當(dāng)值發(fā)生了改變,那么地址也隨之發(fā)生改變;

不可變對象:當(dāng)值發(fā)生了改變,內(nèi)容首地址不發(fā)生變化;

引用計(jì)數(shù)器:用于計(jì)算一個(gè)對象有幾個(gè)指針在引用(有幾個(gè)指針變量指向同一個(gè)內(nèi)存地址);

 

////  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];//注意此時(shí)str1的計(jì)數(shù)器是1    NSLog(@"%lu",[str1 retainCount]); //結(jié)果:1            NSMutableString *str2=[str1 mutableCopy];//注意此時(shí)str2的計(jì)數(shù)器為1,str1的計(jì)數(shù)器還是1    //NSMutableString *str5 =CFRetain((__bridge CFTypeRef)str2);    NSLog(@"retainCount(str1)=%lu,retainCount(str2)=%lu",[str1 retainCount],[str2 retainCount]);    //結(jié)果:retainCount(str1)=1,retainCount(str2)=1            [str2 appendString:@"def"];//改變str2,str1不變    NSLog(@"%zi",str1==str2);//二者不是向同一個(gè)對象,結(jié)果:0    NSLog(@"str1=%@",str1); //結(jié)果:str1=I'm Kenshin.    NSLog(@"str2=%@",str2); //結(jié)果:str2=I'm Kenshin.def            NSLog(@"str1's %lu",[str1 retainCount]);    NSString *str3=[str1 copy];//str3不是產(chǎn)生的新對象而是復(fù)制了對象指針,但是str1的計(jì)數(shù)器+1(當(dāng)然既然str3同樣指向同一個(gè)對象,那么如果計(jì)算str3指向的對象引用計(jì)數(shù)器肯定等于str1的對象引用計(jì)數(shù)器)    NSLog(@"%zi",str1==str3);//二者相等指向同一個(gè)對象,結(jié)果:1    NSLog(@"retainCount(str1)=%lu,retainCount(str3)=%lu",str1.retainCount,str3.retainCount);    //結(jié)果:retainCount(str1)=2,retainCount(str3)=2        //需要注意的是使用copy和mutableCopy是深復(fù)制還是淺復(fù)制不是絕對,關(guān)鍵看由什么對象產(chǎn)生什么樣的對象    NSString *str4=[str2 copy];//由NSMutableString產(chǎn)生了NSString,二者類型都不同肯定是深拷貝,此時(shí)str2的計(jì)數(shù)器還是1,str4的計(jì)數(shù)器也是1    [str2 appendString:@"g"];//改變原對象不影響str4    NSLog(@"%zi",str2==str4); //結(jié)果:0    NSLog(@"str2=%@",str2); //結(jié)果:str2=I'm Kenshin.defg    NSLog(@"str4=%@",str4); //結(jié)果:str4=I'm Kenshin.def        [str1 release];    str1=nil;    [str3 release];//其實(shí)這里也可以調(diào)用str1再次release,因?yàn)樗麄儍蓚€(gè)指向的是同一個(gè)對象(但是一般不建議那么做,不容易理解)    str3=nil;        [str2 release];    str2=nil;    [str4 release];    str4=nil;        //上面只有一種情況是淺拷貝:不可變對象調(diào)用copy方法    }int main(int argc,char *argv[]){    test1();    return 0;}

為了方便大家理解上面的代碼,這里以圖形畫出str1、str2、str3、str4在內(nèi)存中的存儲情況:

MemoryStore

從上面可以清楚的看到str1和str3同時(shí)指向同一個(gè)對象,因此這個(gè)對象的引用計(jì)數(shù)器是2(可以看到兩箭頭指向那個(gè)對象),str2和str4都是兩個(gè)新的對象;另外ObjC引入對象拷貝是為了改變一個(gè)對象不影響另一個(gè)對象,但是我們知道NSString本身就不能改變那么即使我重新復(fù)制一個(gè)對象也沒有任何意義,因此為了性能著想如果通過copy方法產(chǎn)生一個(gè)NSString時(shí)ObjC不會再復(fù)制一個(gè)對象而是將新變量指向同一個(gè)對象。

注意網(wǎng)上很多人支招在ARC模式下可以利用_objc_rootRetainCount()或者CFGetRetainCount()取得retainCount都是不準(zhǔn)確的,特別是在對象拷貝操作之后你會發(fā)現(xiàn)二者取值也是不同的,因此如果大家要查看retainCount最好還是暫時(shí)關(guān)閉ARC。

要想支持copy或者mutablecopy操作那么對象必須實(shí)現(xiàn)NSCoping協(xié)議并實(shí)現(xiàn)-(id)copyWithZone:(NSZone*)zone方法,在Foundation中常用的可復(fù)制對象有: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];}//實(shí)現(xiàn)copy方法-(id)copyWithZone:(NSZone *)zone{    //注意zone是系統(tǒng)已經(jīng)分配好的用于存儲當(dāng)前對象的內(nèi)存    //注意下面創(chuàng)建對象最好不要用[[Person allocWithZone:zone]init],因?yàn)樽宇惾绻麤]有實(shí)現(xiàn)該方法copy時(shí)會調(diào)用父類的copy方法,此時(shí)需要使用子類對象初始化如果此時(shí)用self就可以表示子類對象,還有就是如果子類調(diào)用了父類的這個(gè)方法進(jìn)行重寫copy也需要調(diào)用子類對象而不是父類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定義的時(shí)候使用屬性參數(shù)采用的是copy策略,而根據(jù)前面的知識我們知道NSMutableString的copy策略采用的是對象內(nèi)容復(fù)制,因此如果修改str1不會改變person1.name    [str1 appendString:@" Cui"];    NSLog(@"%@",str1);//結(jié)果:Kenshin Cui    NSLog(@"%@",person1.name); //結(jié)果:Kenshin    }void test2(){    Person *person1=[[Person alloc]init];    person1.name=[NSMutableString stringWithString:@"Kenshin"];    person1.age=28;    Person *person2=[person1 copy];    NSLog(@"%@",person1); //結(jié)果:name=Kenshin,age=0    NSLog(@"%@",person2); //結(jié)果:name=Kenshin,age=0        [person2.name appendString:@" Cui"];        NSLog(@"%@",person1);//結(jié)果:name=Kenshin Cui,age=28    NSLog(@"%@",person2);//結(jié)果:name=Kenshin Cui,age=28}int main(int argc,char *argv[]){    test1();    test2();    return 0;}

在上面的代碼中重點(diǎn)說一下test2這個(gè)方法,在test2方法中我們發(fā)現(xiàn)當(dāng)修改了person2.name屬性之后person1.name也改變了,這是為什么呢?我們可以看到在Person.m中自定義實(shí)現(xiàn)了copy方法,同時(shí)實(shí)現(xiàn)了一個(gè)淺拷貝。之所以說是淺拷貝主要是因?yàn)槲覀兊膎ame屬性參數(shù)是直接賦值完成的,同時(shí)由于name屬性定義時(shí)采用的是assign參數(shù)(默認(rèn)為assign),所以當(dāng)通過copy創(chuàng)建了person2之后其實(shí)person2對象的name屬性和person1指向同一個(gè)NSMutableString對象。通過圖形表示如下:

MemoryStore2

上面test2的寫法純屬為了讓大家了解復(fù)制的原理和本質(zhì),實(shí)際開發(fā)中我們很少會遇到這種情況,首先我們一般定義name的話可能用的是NSString類型,根本也不能修改;其次我們定義字符串類型的話一般使用(copy)參數(shù),同樣可以避免這個(gè)問題(因?yàn)镹SMutableString的copy是深復(fù)制)。那么如果我們非要使用NSMutabeString同時(shí)不使用屬性的copy參數(shù)如何解決這個(gè)問題呢?答案就是使用深復(fù)制,將-(id)copyWithZone:(NSZone *)zone方法中person1.name=_name改為,person1.name=[_name copy];或person1.name=[_name mutablecopy]即可,這樣做也正好滿足我們上面對于深復(fù)制的定義。

補(bǔ)充-NSString的引用計(jì)數(shù)器

在好多語言中字符串都是一個(gè)特殊的對象,在ObjC中也不例外。NSString作為一個(gè)對象類型存儲在堆中,多數(shù)情況下它跟一般的對象類型沒有區(qū)別,但是這里我們需求強(qiáng)調(diào)一點(diǎn)那就是字符串的引用計(jì)數(shù)器。

////  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); //結(jié)果:-1    [str1 retain];    NSLog(@"retainCount(str1)=%i",(unsigned long)str1.retainCount); //結(jié)果:-1        NSString *str2=[NSString stringWithString:@"Kaoru"];    NSLog(@"retainCount(str2)=%i",str2.retainCount); //結(jié)果:-1    [str1 retain];    NSLog(@"retainCount(str2)=%i",str2.retainCount); //結(jié)果:-1    NSString *str2_1=[NSString stringWithString:[NSString stringWithFormat:@"Kaoru %@",@"sun"]];    NSLog(@"retainCount(str2_1)=%i",str2_1.retainCount);//結(jié)果:2     [str2_1 release];    [str2_1 release];                NSString *str3=[NSString stringWithFormat:@"Rosa %@",@"Sun"];    NSLog(@"retainCount(str3)=%i",str3.retainCount); //結(jié)果:1    [str3 retain];    NSLog(@"retainCount(str3)=%i",str3.retainCount); //結(jié)果:2    [str3 release];    [str3 release];        NSString *str4=[NSString stringWithUTF8String:"Jack"];    NSLog(@"retainCount(str4)=%i",str4.retainCount); //結(jié)果:1    [str4 retain];    NSLog(@"retainCount(str4)=%i",str4.retainCount); //結(jié)果:2    [str4 release];    [str4 release];        NSString *str5=[NSString stringWithCString:"Tom" encoding:NSUTF8StringEncoding];    NSLog(@"retainCount(str5)=%i",str5.retainCount); //結(jié)果:1    [str5 retain];    NSLog(@"retainCount(str5)=%i",str5.retainCount); //結(jié)果:2    [str5 release];    [str5 release];                NSMutableString *str6=@"Jerry";    NSLog(@"retainCount(str6)=%i",str6.retainCount); //結(jié)果:-1    [str6 retain];    NSLog(@"retainCount(str6)=%i",str6.retainCount); //結(jié)果:-1    [str6 release];    [str6 release];        NSMutableArray *str7=[NSMutableString stringWithString:@"Lily"];    NSLog(@"retainCount(str7)=%i",str7.retainCount); //結(jié)果:1    [str7 retain];    NSLog(@"retainCount(str7)=%i",str7.retainCount); //結(jié)果:2    [str7 release];    [str7 release];        return 0;}

看完上面的例子如果不了解NSString的處理你也許會有點(diǎn)奇怪(注意上面的代碼請?jiān)赬code5下運(yùn)行)?請看下面的解釋

  • str1是一個(gè)字符串常量,它存儲在常量區(qū),系統(tǒng)不會對它進(jìn)行引用計(jì)數(shù),因此無論是初始化還是做retain操作其引用計(jì)數(shù)器均為-1;
  • str3、str4、str5創(chuàng)建的對象同一般對象類似,存儲在堆中,系統(tǒng)會對其進(jìn)行引用計(jì)數(shù);
  • 采用stringWithString定義的變量有些特殊,當(dāng)后面的字符串是字符串常量,則它本身就作為字符串常用量存儲(str2),類似于str1;如果后面的參數(shù)是通過類似于str3、str4、str5的定義,那么它本身就是一個(gè)普通對象,只是后面的對象引用計(jì)數(shù)器默認(rèn)為1,當(dāng)給它賦值時(shí)會做一次拷貝操作(淺拷貝),引用計(jì)數(shù)器加1,所有str2_1引用計(jì)數(shù)器為2;
  • str6其實(shí)和str1類似,雖然定義的是可變數(shù)組,但是它的本質(zhì)還是字符串常量,事實(shí)上對于可變字符串只有為字符串常量時(shí)引用計(jì)數(shù)器才為-1,其他情況它的引用計(jì)數(shù)器跟一般對象完全一致;

后記:注意上面這段代碼的運(yùn)行結(jié)果是在Xcode5中運(yùn)行的結(jié)果,事實(shí)上針對最新的Xcode6由于LLVM的優(yōu)化,只有str2_1和str7的引用計(jì)數(shù)器為1(str7 retain一次后第二次為2),其他均為-1。

文件操作

在今天的最后一節(jié)內(nèi)容中讓我們看一下Foundation中文件操作,下面將以一個(gè)例子進(jìn)行說明:

////  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];        //獲得當(dāng)前程序所在目錄(當(dāng)然可以改變)    NSString *currentPath=[manager currentDirectoryPath];    NSLog(@"current path is :%@",currentPath);    //結(jié)果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug        //創(chuàng)建目錄    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!");    }        //目錄重命名,如果需要?jiǎng)h除目錄只要調(diào)用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);    }        //改變當(dāng)前目錄    if([manager changeCurrentDirectoryPath:newPath]==NO){        NSLog(@"Change current directory failed!");    }    NSLog(@"current path is :%@",[manager currentDirectoryPath]);    //結(jié)果:current path is :/Users/kenshincui/Desktop/myNewDocument        //遍歷整個(gè)目錄    NSString *path;    NSDirectoryEnumerator *directoryEnumerator= [manager enumeratorAtPath:newPath];    while (path=[directoryEnumerator nextObject]) {        NSLog(@"%@",path);    }    /*結(jié)果:     documents     est.txt    */        //或者這樣遍歷    NSArray *paths= [manager contentsOfDirectoryAtPath:newPath error:nil];    NSObject *p;    for (p in paths) {        NSLog(@"%@",p);    }    /*結(jié)果:     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";        //判斷文件是否存在,這個(gè)方法也可以判斷目錄是否存在,這要后面的參數(shù)設(shè)置位YES    if ([manager fileExistsAtPath:filePath isDirectory:NO]) {        NSLog(@"File exists!");    }        //文件是否可讀    if([manager isReadableFileAtPath:filePath]){        NSLog(@"File is readable!");    }        //判斷兩個(gè)文件內(nèi)容是否相等    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]);    }    /*結(jié)果:         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];    }//文件操作--文件內(nèi)容操作(NSData,非結(jié)構(gòu)化字節(jié)流對象,有緩沖區(qū)管理機(jī)制,可用于網(wǎng)絡(luò)傳輸)void test3(){    NSFileManager *manager=[NSFileManager defaultManager];    NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt";    NSData *data=[manager contentsAtPath:filePath];    NSLog(@"%@",data);//存儲的是二進(jìn)制字節(jié)流    //結(jié)果:<68656c6c 6f20776f 726c642c e4b896e7 958ce4bd a0e5a5bd efbc81>        //NSData轉(zhuǎn)化成字符串    NSString *str1=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];    NSLog(@"%@",str1);    //結(jié)果:hello world,世界你好!        //字符串轉(zhuǎn)化成NSData    NSString *str2=@"Kenshin";    NSData *data2=[str2 dataUsingEncoding:NSUTF8StringEncoding];    NSLog(@"%@",data2);        //當(dāng)然一般如果僅僅是簡單讀取文件內(nèi)容,直接用戶NSString方法即可    NSString *content=[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];    NSLog(@"%@",content);    //結(jié)果:hello world,世界你好!    }//文件操作--細(xì)粒度控制文件,文件操作柄void test4(){    NSFileManager *manager=[NSFileManager defaultManager];    NSString *filePath=@"/Users/kenshincui/Desktop/myNewDocument/test2.txt";        //以只讀方式打開文件    NSFileHandle *fileHandle=[NSFileHandle fileHandleForReadingAtPath:filePath];//注意這個(gè)方法返回類型為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];//寫入文件內(nèi)容        [fileHandle2 closeFile];//關(guān)閉文件        //定位到指定位置,默認(rèn)在文件開頭    [fileHandle seekToFileOffset:12];    NSData *data2= [fileHandle readDataToEndOfFile];    NSLog(@"data2=%@",[[NSString alloc]initWithData:data2 encoding:NSUTF8StringEncoding]);    //結(jié)果:data2=世界你好!        [fileHandle seekToFileOffset:6];    NSData *data3=[fileHandle readDataOfLength:5];    NSLog(@"data3=%@",[[NSString alloc]initWithData:data3 encoding:NSUTF8StringEncoding]);    //結(jié)果:data3=world        [fileHandle closeFile];    }//文件路徑void test5(){    NSString *filePath=@"/Users/kenshincui/Desktop/myDocument";    NSString *filePath2=@"/Users/kenshincui/Desktop/test.txt";    //臨時(shí)文件所在目錄    NSString *path=NSTemporaryDirectory();    NSLog(@"temporary directory is :%@",path);    //結(jié)果:/var/folders/h6/lss6gncs509c2pgzgty3wd_40000gn/T/    NSString *lastComponent= [filePath lastPathComponent];    NSLog(@"%@",lastComponent); //結(jié)果:myDocument        NSLog(@"%@",[filePath stringByDeletingLastPathComponent]);    //結(jié)果:/Users/kenshincui/Desktop    NSLog(@"%@",[filePath stringByAppendingPathComponent:@"Pictrues"]);    //結(jié)果:/Users/kenshincui/Desktop/myDocument/Pictrues    NSLog(@"%@",[filePath2 pathExtension]);    //結(jié)果:txt        [[filePath pathComponents] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {        NSLog(@"%i=%@",idx,obj);    }];    /*結(jié)果:     0=/     1=Users     2=kenshincui     3=Desktop     4=myDocument     */        }//文件操作--NSURLvoid test6(){    NSURL *url=[NSURL URLWithString:@"http://developer.apple.com"];    NSString *str1=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];    NSLog(@"%@",str1);}//文件操作--NSBundle,程序包,一般用于獲取Resource中的資源(當(dāng)然由于當(dāng)前并非IOS應(yīng)用沒有程序包,只是表示當(dāng)前程序運(yùn)行路徑)//在ios中經(jīng)常用于讀取應(yīng)用程序中的資源文件,如圖片、聲音、視頻等void test7(){    //在程序包所在目錄創(chuàng)建一個(gè)文件    NSFileManager *manager=[NSFileManager defaultManager];    NSString *currentPath=[manager currentDirectoryPath];    NSLog(@"current path is :%@",currentPath);    //結(jié)果: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在程序包所在目錄查找對應(yīng)的文件    NSBundle *bundle=[NSBundle mainBundle];//主要操作程序包所在目錄    //如果有test.txt則返回路徑,否則返回nil    NSString *path=[bundle pathForResource:@"test" ofType:@"txt"];//也可以寫成:[bundle pathForResource:@"instructions.txt" ofType:nil];    NSLog(@"%@",path);    //結(jié)果:/Users/kenshincui/Library/Developer/Xcode/DerivedData/FoundationFramework-awxjohcpgsqcpsanqofqogwbqgbx/Build/Products/Debug/test.txt    NSLog(@"%@",[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]);    //結(jié)果:Hello,world!        //假設(shè)我們在程序運(yùn)行創(chuàng)建一個(gè)Resources目錄,并且其中新建pic.jpg,那么用下面的方法獲得這個(gè)文件完整路徑    NSString *path1= [bundle pathForResource:@"pic" ofType:@"jpg" inDirectory:@"Resources"];    NSLog(@"%@",path1);    //結(jié)果:/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;}

歸檔

歸檔,在其他語言中又叫“序列化”,就是將對象保存到硬盤;解檔,在其他語言又叫“反序列化”就是將硬盤文件還原成對象。其實(shí)歸檔就是數(shù)據(jù)存儲的過程,在IOS中數(shù)據(jù)的存儲有五種方式:

  1. xml屬性列表(plist歸檔)

  2. NSUserDefaults(偏好設(shè)置)

  3. NSKeyedArchiver歸檔(加密形式)

  4. SQLite3(嵌入式數(shù)據(jù)庫)

  5. Core Data(面向?qū)ο蠓绞降那度胧綌?shù)據(jù)庫)

當(dāng)然關(guān)于2、4、5點(diǎn)不是我們今天介紹的重點(diǎn),這個(gè)在IOS開發(fā)過程中我們會重點(diǎn)說到。

xml屬性列表

首先我們先來看一下xml屬性列表,xml屬性列表進(jìn)行歸檔的方式是將對象存儲在一個(gè)plist文件中,這個(gè)操作起來比較簡單,其實(shí)相當(dāng)于xml序列化。但是同時(shí)它也有缺點(diǎn):一是這種方式是明文保存的;二是這種方式操作的對象有限,只有NSArray、NSMutableArray、NSDictionary、NSMutableDictionary支持(歸檔時(shí)只要調(diào)用對應(yīng)的writeToFile方法即可,解檔調(diào)用arrayWithContentsOfFile或dictionaryWithContentsOfFile,注意像NSString、NSNumber、NSData即使有這個(gè)方法它存儲的也不是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(){    //數(shù)組    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);    }];    /*結(jié)果:     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);    }];    /*結(jié)果:     dic2[height]=172.5     dic2[age]=28     dic2[name]=Kenshin     */}int main(int argc,char *argv[]){        test1();        return 0;}

生成的文件如下

arrayXml

dicXml

NSKeyedArchiver歸檔

如果要針對更多對象歸檔或者需要?dú)w檔時(shí)能夠加密的話就需要使用NSKeyedArchiver進(jìn)行歸檔和解檔,使用這種方式歸檔的范圍更廣而且歸檔內(nèi)容是密文存儲。從歸檔范圍來講NSKeyedArchiver適合所有ObjC對象,但是對于自定義對象我們需要實(shí)現(xiàn)NSCoding協(xié)議;從歸檔方式來講NSKeyedArchiver分為簡單歸檔和復(fù)雜對象歸檔,簡單歸檔就是針對單個(gè)對象可以直接將對象作為根對象(不用設(shè)置key),復(fù)雜對象就是針對多個(gè)對象,存儲時(shí)不同對象需要設(shè)置不同的Key。

首先看一下系統(tǒng)對象兩種歸檔方式(注意由于本章主要介紹Foundation內(nèi)容,下面的程序是OS X命令行程序并沒有創(chuàng)建成iOS應(yīng)用,如果移植到到iOS應(yīng)用下運(yùn)行將NSArchiver和NSUnarchiver換成NSKeyedArchiver和NSKeyedUnarchiver。雖然在Foundation部分iOS和OS X在設(shè)計(jì)上盡可能通用但是還存在著細(xì)微差別。)

////  main.m//  FoundationFramework////  Created by Kenshin Cui on 14-2-16.//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#import <Foundation/Foundation.h>//系統(tǒng)對象簡單歸檔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);//結(jié)果: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);    }];    /*結(jié)果:     array2[0]=Kenshin     array2[1]=Kaoru     array2[2]=Rosa     */}//系統(tǒng)復(fù)雜對象歸檔(多對象歸檔)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};        //同時(shí)對多個(gè)對象進(jìn)行歸檔    NSMutableData *data1=[[NSMutableData alloc]init];//定義一個(gè)NSMutableData用于臨時(shí)存放數(shù)據(jù)    NSKeyedArchiver *archiver=[[NSKeyedArchiver alloc]initForWritingWithMutableData:data1];//定義歸檔對象    [archiver encodeInt:int1 forKey:@"int"];//對int1歸檔并指定一個(gè)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];//結(jié)束歸檔        [data1 writeToFile:path1 atomically:YES];//寫入文件                /*解檔*/    int int2;    CGSize size2;    NSNumber *number2;    NSString *str2;    NSArray *array2;    NSDictionary *dic2;        NSData *data2=[[NSData alloc]initWithContentsOfFile:path1];//讀出數(shù)據(jù)到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);    /*結(jié)果:     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;}

接下來看一下自定義的對象如何歸檔,上面說了如果要對自定義對象進(jìn)行歸檔那么這個(gè)對象必須實(shí)現(xiàn)NSCoding協(xié)議,在這個(gè)協(xié)議中有兩個(gè)方法都必須實(shí)現(xiàn):

-(void)encodeWithCoder:(NSCoder *)aCoder;通過給定的Archiver對消息接收者進(jìn)行編碼;

-(id)initWithCoder:(NSCoder *)aDecoder;從一個(gè)給定的Unarchiver的數(shù)據(jù)返回一個(gè)初始化對象;

這兩個(gè)方法分別在歸檔和解檔時(shí)調(diào)用。下面通過一個(gè)例子進(jìn)行演示(注意對于自定義類的多對象歸檔與系統(tǒng)類多對象歸檔完全一樣,代碼中不再演示):

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);    /*結(jié)果:     name=Kenshin,age=28,height=0.00,birthday=1986-08-08     */        return 0;}
今天的文章就到這里了,內(nèi)容確實(shí)不少,但是要用一篇文章把Foundation的所有內(nèi)容說完也是完全不現(xiàn)實(shí)的。這篇文章有一部分內(nèi)容并沒有詳細(xì)的解釋代碼,這部分內(nèi)容主要是個(gè)人認(rèn)為比較簡單,通過注釋大家就可以理解。不過并不是說這部分內(nèi)容不重要,而是這些內(nèi)容多數(shù)是記憶性的東西,不需要過多解釋。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 阿尔山市| 宣武区| 习水县| 新乡市| 芦山县| 青冈县| 彰化县| 阿尔山市| 安义县| 河西区| 侯马市| 慈利县| 福泉市| 区。| 托里县| 土默特右旗| 永和县| 西青区| 恩平市| 罗源县| 锡林郭勒盟| 广灵县| 花垣县| 卓资县| 娄底市| 库伦旗| 修文县| 杭锦旗| 海安县| 西峡县| 临沧市| 江华| 社会| 鞍山市| 独山县| 洪雅县| 遂平县| 霍城县| 江油市| 通榆县| 彰化县|