Foundation框架中常用类的介绍
http://blog.csdn.net/mengtnt/article/details/6087536
Foundation框架的架構(gòu)
?
??? cocoa程序編寫主要用到2個(gè)框架Foundation和ApplicationKit。其中Foundation框架主要定義了一些基礎(chǔ)類,供程序員 來使用,而Application kit主要是一些用戶界面設(shè)計(jì)的類。Foundation框架中的所有類都繼承自NSObject這個(gè)對象,等下會(huì)講到這個(gè)對象,這里就暫且知道有這樣一 個(gè)超類就行了。Foundation框架的主要目標(biāo)有一下幾點(diǎn):
1) 為內(nèi)存管理,對象的創(chuàng)建,消息的傳遞定義基本的對象。
2)用Unicode編碼定義字符串類,以及方便的支持語言本地化
3)支持對象的持久保存和發(fā)布。
這幾點(diǎn)都是apple官方文檔上寫的設(shè)計(jì)Foundation框架的目標(biāo)。
??? 下面就分析下Foundation類設(shè)計(jì)的大致策略,首先是建立對象和清理對象的策略,對象釋放池NSAutorelasePool是一個(gè)重要的對象,用 來自動(dòng)回收對象,從而讓程序員方便的進(jìn)行內(nèi)存管理。其次就是可變大小的對象(例如NSMutableString),這些對象可以對我們常用的容器類,例 如數(shù)組,字典,集合,堆棧進(jìn)行方便的擴(kuò)展,而不必關(guān)系這些容器擴(kuò)展的方法。第三點(diǎn)就是類簇,就是一個(gè)抽象類和一些具體類的組合,這樣就組成了我們需要的各 種對象和方法,方便以后的調(diào)用。最后一點(diǎn)就是通知NSNotificationCentor,其實(shí)這個(gè)特點(diǎn)用到了一個(gè)重要的設(shè)計(jì)模式,觀察者模式。相信如 果看過五人組寫的設(shè)計(jì)模式這本書,你一定對這個(gè)方法深有體會(huì),因?yàn)樗窃O(shè)計(jì)模式中一個(gè)重要的方法。NSNotificationCentor類就是在這個(gè) 基礎(chǔ)上設(shè)計(jì)的。
??? 那么Foundation框架到底有那些類組成哪?我會(huì)在以后的博客里,挑選一些常用的類進(jìn)行詳細(xì)的分析。這里就大致說以下Foundation框架有那 些類組成吧。Foundation類的根是NSObject和NSCoping協(xié)議組成的,這兩個(gè)定義了類的基本屬性和方法。繼承自NSObject的類 大致可以分為這樣幾類:基本的數(shù)據(jù)類型的類,如 NSNumber 、一些集合類如NSString NSArray、一些代表系統(tǒng)信息的類如NSDate、還有一些系統(tǒng)實(shí)體的類如NSTread NSTast等等。
NSObject介紹
??? 假如沒有面向?qū)ο蟮恼Z言,那么結(jié)構(gòu)化的程序設(shè)計(jì)語言如何模擬類哪?那自然就想到了結(jié)構(gòu)體,其實(shí)objective c是在c語言的基礎(chǔ)上發(fā)展的,同樣NSObject也是用結(jié)構(gòu)體來實(shí)現(xiàn)的。首先來看下一段結(jié)構(gòu)體模擬類的代碼吧。
typedef struct my_objc_class *MetaClass;
typedef struct my_objc_class *MyClass;
struct my_objc_class {????
??? MetaClass?????????? class_pointer;????????
??? struct my_objc_class*? super_class;???????????
??? const char*???????? name;????????????????
??? long??????????????? version;??????????????
??? unsigned long?????? info;?????????????????
??? long??????????????? instance_size;?????????
??? struct objc_ivar_list* ivars;?????????????
??? struct objc_method_list*? methods;?????????
??? struct sarray *??? dtable;?????????????????
??? struct my_objc_class* subclass_list;??????????
??? struct my_objc_class* sibling_class;
??? struct objc_protocol_list *protocols;????????
??? void* gc_object_type;
};
//這里就是自己定義一個(gè)類了。
MyClass student;
估計(jì)你看完這個(gè)結(jié)構(gòu)體,會(huì)驚奇的說原來這就是NSObject啊,其實(shí)這不是NSObject的原型,因?yàn)樘O果公司一向不喜歡開源,她的代碼我們怎 么可能得到那。上面的結(jié)構(gòu)體,是GCC中定義的開源代碼,從網(wǎng)上都可以下到,這就是一個(gè)類是如何用結(jié)構(gòu)體實(shí)現(xiàn)的。下面我們就來逐行分析下這個(gè)結(jié)構(gòu)體吧,來 揭示一下類的本質(zhì)。
1)class_pointer 顧名思義就是這個(gè)結(jié)構(gòu)體本身的一個(gè)指針,相信大部人都知道java和c++中的this關(guān)鍵字的用法吧,在c++中this指針就是這里的class_point。而objective c則是用的self來表示自身的指針的。
2)super_class 看到這里就知道繼承是怎么回事了吧,就是在結(jié)構(gòu)體里放上一個(gè)指針指向它的父節(jié)點(diǎn)。懂得了這點(diǎn)如果想要實(shí)現(xiàn)c++中的多重繼承,無非就是用指針數(shù)組或者鏈表就可以了。
3)name version和info我要放到一塊說了,因?yàn)樗齻兌即笸‘悺ame就是你定義的類的名字。任何產(chǎn)品都要有個(gè)版本吧,類同樣也是人們設(shè)計(jì)出來的產(chǎn) 品,version就是要給你的類加一個(gè)版本號,方便日后升級。info就是相當(dāng)于一個(gè)ID,來區(qū)分你創(chuàng)建了多少個(gè)這樣的結(jié)構(gòu)體,也就是類。
4)instance_size 這就是類的關(guān)鍵部分,在類中叫成員變量,這個(gè)大小是如何分配的,是根據(jù)你在類中定義了多少實(shí)例。這樣在這個(gè)類去初始化的時(shí)候,就會(huì)讀取instance_size中的數(shù)據(jù),在c語言中就用malloc給這個(gè)結(jié)構(gòu)體分配大小。
5)ivars 表示的是類成員變量的列表,成員變量在分配好大小之后,ivars就存取了她們的地址,從而可以方便的訪問到成員變量。所以說c++對類成員變量作用區(qū)域 的限制,如pravite都是語法上的限制,如果你知道類是如何設(shè)計(jì)的,就可以先讀取類的地址,接著讓指針偏移一個(gè)變量的大小就可以訪問到類中 pravite的變量了。
6)methods 方法列表,和實(shí)例變量設(shè)計(jì)的類似,無非這個(gè)列表是個(gè)函數(shù)指針列表吧了,存的都是函數(shù)指針。這里就不贅余了。
7)dtable 這個(gè)要就是一些語言可以實(shí)現(xiàn)動(dòng)態(tài)綁定的關(guān)鍵,在c++中這就是一個(gè)虛表,當(dāng)這個(gè)虛表中有數(shù)據(jù)的時(shí)候,函數(shù)調(diào)用的時(shí)候就會(huì)首先在methods列表中找到方 法的地址,然后從dtable查找符合這個(gè)方法應(yīng)該有多少偏移量,從而訪問到正確的地址。objective c中消息同樣也是這樣實(shí)現(xiàn)的。下面是objective c每次方法調(diào)用時(shí)都會(huì)調(diào)用lookup這個(gè)方法。
objc_msg_lookup(id?receiver,?SEL?op)
{
? if (receiver)
??? return ?sarray_get(receiver -> class_pointer -> dtable,?(sidx)op);
? else
??? return ?nil_method;
}
8)subclass_list 是子類的列表指針這里不再贅余。
9) sibling_class 是兄弟類的列表,類的結(jié)構(gòu)明顯看出來是數(shù)據(jù)結(jié)構(gòu)中樹的原型,用鏈表表示樹的方法多種多樣,這里用到的是孩子兄弟表示法。
10)protocols 這里特意用這個(gè)名字是為了方便說明objectivc的協(xié)議,如果用面向?qū)ο蟮慕y(tǒng)一定義解釋的話,這個(gè)指針是用來實(shí)現(xiàn)接口的,在c++中叫純虛對象。
11)gc_object_type 類方法和類變量從那而來的,這就是答案。
有了上面的基礎(chǔ)下面介紹SELECTOR和IMP就容易多了。
SELECTOR和IMP
下面的內(nèi)容主要以代碼的形式演示下,在cocoa中類的方法調(diào)用是如何實(shí)現(xiàn)的。這里我定義了2個(gè)很簡單的類純屬是用來模擬數(shù)據(jù)的。 athlete和footballPlayer。其中footballPlayer繼承自athlete,代碼如下:
//
//? athlete.h
//? SelectorAndFuntion
//
//? Created by mengtnt on 10-12-8.
//? Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface athlete : NSObject
{
??? NSString *name;
}
- (void)show;
@end
#import "athlete.h"
@implementation athlete
- (id)init
{
??? self = [super init];
??? if (self)
??? {
??? ??? name = [[NSString alloc] initWithString:@"Rossi"];
??? }
??? return self;
}
- (void)dealloc
{
??? [name release];
??? [super dealloc];
}
- (void)show
{
??? NSLog(@"My name is %@/n",name);
}
@end
//
//? footballPlayer.h
//? SelectorAndFuntion
//
//? Created by mengtnt on 10-12-8.
//? Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "athlete.h"
@interface footballPlayer : athlete
{
??? NSNumber *goalNumber;
}
@end
#import "footballPlayer.h"
@implementation footballPlayer
- (id)init
{
??? self = [super init];
??? if (self)
??? {
??? ??? goalNumber = [[NSNumber alloc] initWithUnsignedInt:100];
??? }
??? return self;
}
- (void)dealloc
{
??? [goalNumber release];
??? [super dealloc];
}
- (void)show
{
??? NSLog(@"Goal is %@/n",goalNumber);
}
@end
那么利用上面兩個(gè)數(shù)據(jù)類,下面這個(gè)類就模擬了cocoa中消息的發(fā)送。
//? doProx.h
//? SelectorAndFuntion
//? 這個(gè)類是用來演示Class,SEL,IMP,函數(shù)指針在objective c中如何使用。
//? 1.SEL IMP 函數(shù)名字的關(guān)系。其中SEL是apple給每個(gè)函數(shù)分配的ID,IMP代表函數(shù)指針。關(guān)系圖如下:
//?????????? footballPlayer 類
//? 方法名字??????? 方法ID(假設(shè))??????? 地址(假設(shè))
//? show???????????? 1001??????? ? ? ? ?? 0x2001
//? 2.其中會(huì)用到獲取函數(shù)ID的方法selector和通過函數(shù)ID調(diào)用函數(shù)的方法performSelector,等等這些函數(shù)的用法。
//? 另外,反之我們可以用NSSelectorFromString方法來查找此函數(shù)名字的ID。
//? 3.我們可以利用methodForSelector來獲得函數(shù)的指針。并且還利用函數(shù)指針,來展示objective c中的performSelector是如何實(shí)現(xiàn)的。
//? 4.同樣我們可以通過一個(gè)普通的字符串取得這個(gè)Class類型(方法NSClassFromString),也可以通過我們生成的對象取得這個(gè)Class.
//? Selector和Class比較類似,而Class類型獲得的方法ClassName.不同的地方是Selector用于表示方法.
//? Created by mengtnt on 10-12-8.
//? Copyright 2010 __MyCompanyName__. All rights reserved.
#import <Cocoa/Cocoa.h>
#define SHOW @"show"??? //函數(shù)show的字符串。
#define FOOTBALLPLAYER_CLASS @"footballPlayer"? //類footballPlayer的字符串
@interface doProx : NSObject
{
??? id athleteInstance[2];??? //因?yàn)橐獎(jiǎng)討B(tài)的調(diào)用athlete中的show和footballPlayer的show方法,所以要定義為id類型。
??? SEL show_SEL;??
??? IMP show_IMP;
??? void(*show_Func) (id, SEL);? //函數(shù)指針是用來展示IMP在cocoa中是如何實(shí)現(xiàn)的。因?yàn)镮MP其實(shí)定義就是函數(shù)指針。
??? Class footBallPlayerClass;
}
- (void)setSEL;
- (void)showResult;
@end
#import "doProx.h"
#import "athlete.h"
#import "footballPlayer.h"?? //在這里才包含兩個(gè)頭文件,這樣才能體現(xiàn)程序動(dòng)態(tài)執(zhí)行的效果。
@implementation doProx
//分別給athlete賦予不同的對象
- (id)init
{
??? self = [super init];
??? //第一種獲得類對象的方法,是用類方法調(diào)用獲得此對象
??? athleteInstance[0] = [[athlete alloc] init];
???
??? //第二種獲得類對象的方法,首先通過類的字符串獲得類的類型,然后用此類型的類方法調(diào)用創(chuàng)建對象。
??? footBallPlayerClass = NSClassFromString(FOOTBALLPLAYER_CLASS);
??? athleteInstance[1] = [[footBallPlayerClass alloc] init];
??? return self;
}
- (void)dealloc
{
??? [athleteInstance[0] release];
??? [athleteInstance[1] release];
??? [super dealloc];
}
//如何獲取SEL變量的值。SEL的值是根據(jù)函數(shù)名字獲得的,相同的名字具有相同的ID。
- (void)setSEL
{
??? //方法一用函數(shù)名字獲得。
??? //show_SEL = @selector(show);
???
??? //方法二用函數(shù)的字符串獲得。
??? show_SEL = NSSelectorFromString(SHOW);
}
- (void)showResult
{
??? show_IMP = [athleteInstance[0] methodForSelector:show_SEL];
??? show_IMP(athleteInstance[0],show_SEL);
???
??? show_Func=(void (*)(id, SEL)) [athleteInstance[1] methodForSelector:show_SEL];
??? show_Func(athleteInstance[1],show_SEL);
???
??? //展現(xiàn)perform的用法,判斷這個(gè)對象必須是footballPlayer類型才能執(zhí)行。
??? for(int i = 0;i < 2;i++)
??? {
??? ??? if ([[athleteInstance[i] className] isEqualToString:FOOTBALLPLAYER_CLASS])
??? ??? {
??? ??? ??? [athleteInstance[i] performSelector:show_SEL];
??? ??? }
??? }
???
??? NSString *myName = NSStringFromSelector(_cmd);
??? NSLog(@"Running in the method of %@", myName);
}
@end
然后在主函數(shù)里面調(diào)用這些方法。
#import <Foundation/Foundation.h>
#import "doProx.h"
int main (int argc, const char * argv[])
{
??? NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
??? doProx *proxy = [[doProx alloc] init];
???
??? [proxy setSEL];
??? [proxy showResult];
??? [pool drain];
??? return 0;
}
有興趣的可以把代碼復(fù)制過去調(diào)試下,在debuger中觀察各個(gè)實(shí)例變量和方法的指針是如何變化的,相信有了這些基礎(chǔ)以后學(xué)習(xí)Foundation框架中的常用類就不會(huì)有什么困難了。
NSString 、NSMutableString類
??? cocoa把字符串處理封裝到NSString類中了,這個(gè)類提供了字符串處理的常用方法,詳細(xì)請見apple develop document。在這里你要了解到NSString類的那些特征那,下面請看一段代碼:
??? NSString *temp =[[NSString alloc] initWithString:@"test"];
??? //NSLog(@"%d",[temp retainCount]);
??? [temp release];
??? //NSLog(@"%d",[temp retainCount]);
??? NSMutableString *str=[[NSMutableString alloc] initWithString:temp];
??? [str appendFormat:@"NSString"];
??? NSLog(@"%@",str);
你猜NSLog會(huì)輸出什么,是我們想要的testNSString么?有興趣的可以在xcode中創(chuàng)建一個(gè)控制臺程序,把上面的代碼復(fù)制進(jìn)去,可以 看到確實(shí)是我們預(yù)期的結(jié)果。學(xué)習(xí)過objective c內(nèi)存管理的肯定就會(huì)有疑問了,temp已經(jīng)釋放了,為什么str中還能和temp中的字符串拼接那?
為了揭開NSString這個(gè)類的秘密,首先把代碼中被注釋的那兩句話,在程序中一同運(yùn)行。那么retainCount又是什么那?引用計(jì)數(shù),這個(gè) 你不會(huì)沒有聽過吧,那你就要再好好學(xué)習(xí)下objective c的內(nèi)存管理了。程序再次運(yùn)行時(shí),你會(huì)發(fā)現(xiàn)控制臺中會(huì)輸出兩個(gè)-1,也就是alloc和release根本就沒有起到任何作用,難道NSString類不 適用于objective c的內(nèi)存管理么?顯然不是,原因就在于NSString類中的字符串都定義在常量區(qū),常量區(qū)并不是程序員為對象在內(nèi)存中申請的空間,而是編譯起給一些變量 分配的空間,所以說你根本無法取得它的引用計(jì)數(shù),因?yàn)檫@個(gè)字符串的分配,根本不受你的控制,完全是編譯起去控制的。所以你看到的都是-1。那么如果給 NSMutableString類型的str取retainCount那答案會(huì)是什么哪?有興趣的可以實(shí)驗(yàn)下,應(yīng)該是1。因?yàn)?NSMutableString雖說它初始化的字符串在常量區(qū),但是NSMutalbeString不像NSString簡單的存取字符串的信息,它還要 存取字符串的容量以及一些其他信息供字符串?dāng)U展,所以自然和NSString就不太一樣了。具體NSMutableString是怎么實(shí)現(xiàn)的那就要問問 apple的工程師了。
NSArray NSMutableString類
??? 首先還是先看段代碼,眼見為實(shí),代碼可以說明一切。假如你有兩個(gè)類Person和Animal那么你就可以寫如下的代碼,來訪問你定義再array對象中的實(shí)例了:
??? Person *aMan = [[Person alloc] init];
??? Animal *dog?? = [[Animal alloc] init];
??? NSArray *aryMammal = [[NSArray arrayWithObjects:aMan,dog]];
??? [aMan release];
??? [dog release];
??? for(id someThing for aryMammal)
??? {
???????? NSLog(@"%@", [someThing getName]];? //假如說你定義的類有這個(gè)方法可以獲得對象的名字
??? }
按照我們學(xué)過的objective c內(nèi)存管理的理論分析的話,程序會(huì)在for循環(huán)中,拋出一個(gè)不能識別的selector發(fā)向一個(gè)實(shí)例的異常。但是你可以運(yùn)行一下,程序非常的正常,沒有任 何的異常。這又是什么原因哪?先不急著看下面的分析,你可以用上面的策略retainCount來看下對象aMan和dog的變化。之后你就很容易發(fā)現(xiàn)問 題在哪里了。下面還是為一些不愿動(dòng)手的同志,分析一下結(jié)果吧。如果照上面所說的在NSArray后面用retainCount來獲取aMan和dog的的 引用計(jì)數(shù)的,你會(huì)發(fā)現(xiàn)這兩個(gè)實(shí)例的retainCount都變成了2,自然release之后對象還是沒有銷毀的。所以由這里可以推測出我們向一個(gè)容器里 面放對象的時(shí)候,對象的引用計(jì)數(shù)會(huì)自動(dòng)加1,apple工程師這樣設(shè)計(jì)就可以大大減少程序崩潰的可能性。
??? 下面來看下NSMutableArray的一些特征。當(dāng)你想要遍歷一個(gè)NSMutableArray的時(shí)候,然后找到某個(gè)特殊的對象,用另外一個(gè)對象替代這個(gè)對象的時(shí)候,代碼如下:
?? int i = 0;
??? for(id temp in mutableAry)
?? {
??????? if([temp equal:aObject])
??????????? [mutableAry replaceObjectAtIndex:i withObject:aObject];
??????? i++;
?? }
這樣的代碼可以運(yùn)行么?答案是只要你的程序進(jìn)到了if語句里面,下次執(zhí)行for循環(huán)的時(shí)候程序就會(huì)崩潰,報(bào)出的錯(cuò)誤是bad access,在之后的博客里我會(huì)和大家一塊分享下,xcode程序運(yùn)行中的常見錯(cuò)誤。下面就來分析下這種錯(cuò)誤的原因吧。 用for(id temp in mutableArray)的時(shí)候,切記不能在for循環(huán)中為mutableArray添加任何東西,因?yàn)閒or循環(huán)在開始的時(shí)候,會(huì)把a(bǔ)rray中的所 有數(shù)據(jù)都放到一個(gè)stack中,stack中存著array中對象的指針。如果你改變了array中的對象,原來對象的指針就銷毀了,而stack中仍然 存著這個(gè)指針,訪問的時(shí)候程序會(huì)bad access從而crash。
??? 下面再來看下NSArray的一個(gè)特殊的用法,就是在數(shù)組中放置dictionary的時(shí)候,數(shù)組同樣可以用valueForKey的方法來訪問dictionary中的value。代碼演示如下:
? ? NSDictionary *dic1 = [NSDictionary dictionaryWithObjectsAndKeys:@"1",@"sky",nil];
?? ?NSDictionary *dic2 = [NSDictionary dictionaryWithObjectsAndKeys:@"2",@"zhiwei",nil];
??? NSDictionary *dic3 = [NSDictionary dictionaryWithObjectsAndKeys:@"1",@"mengtnt",nil];
??? NSMutableArray *ary = [[NSMutableArray alloc] init];
?? ?[ary insertObject:dic1 atIndex:0];
?? ?[ary insertObject:dic2 atIndex:0];
?? ?[ary insertObject:dic3 atIndex:0];
?? ?NSString *str = [[ary valueForKey:@"1"] objectAtIndex:1];
??? NSLog(@"%@",str);
在從array中取得dictionary的value的時(shí)候,切記要指定index因?yàn)閿?shù)組中的dictionary可能有好多key為1的數(shù) 據(jù),它會(huì)根據(jù)index位置獲得正確的數(shù)據(jù),如果上面的程序這樣寫NSString *str = [[ary valueForKey:@"1"] objectAtIndex:0];那么str中應(yīng)該存取的就是mengtnt,而如果objectAtIndex:2 那結(jié)果會(huì)輸出一個(gè)Null。默認(rèn)情況下如果在相應(yīng)的位置沒有這個(gè)dictionary的key,編譯器會(huì)自動(dòng)給這個(gè)位置加一個(gè)NSNull的對象,大家可 不要搞混了,NSNull也是個(gè)對象,也是繼承自NSObject,千萬不能把它當(dāng)作nil處理。只不過apple為了在集合類中表示空對象而定義的一個(gè) 類,因?yàn)椴豢赡茉诩现须S便插入nil對象。這樣就可以避免程序隨便的進(jìn)入nil對象,而造成程序異常。。
??? 首先來看下一個(gè)操作文件以及目錄的重要類NSFileManager。下面還是看一段代碼,來一一說明此類的用法
??? NSFileManager *fm;
??? NSDirectoryEnumerator *dirEnum;
??? NSArray *dirArray;
??? ?// 需要?jiǎng)?chuàng)建一個(gè)file manager的實(shí)例
??? fm = [NSFileManager defaultManager];
???
??? // 獲取當(dāng)前工作目錄的路徑
??? path = [fm currentDirectoryPath];
???
??? // 遍歷這個(gè)目錄
??? dirEnum = [fm enumeratorAtPath: path];
??? NSLog(@"Contents of %@:", path);
??? while ((path = [dirEnum nextObject]) != nil)
??? {
??? ??? ???
??? ??? ??? NSLog(@"%@", path);
??? }
??? // 另一種遍歷目錄的方法
???
??? dirArray = [fm contentsOfDirectoryAtPath: [fm currentDirectoryPath] error: nil];
??? NSLog(@"Contents using contentsOfDirectoryAtPath:");
??? for (path in dirArray)
??? ??? NSLog(@"%@", path);
相信仔細(xì)看了這些代碼之后,會(huì)對NSFileManager這個(gè)類如何遍歷目錄,有了一定的認(rèn)識吧。其實(shí)這些代碼都非常簡單,只要查看apple developer文檔都能找到的。雖說理解起來簡單,但是有時(shí)候一動(dòng)手寫代碼還是會(huì)遇到很多問題的。例如下面
??? ??? NSArray *aryProvsioning = [FileManager contentsOfDirectoryAtPath:@"/vault/provisioning" error:nil];
??? ??? for(NSString* provisioningFile in aryProvsioning)
??? ??? {
??? ??? ??? NSLog(@"delete file:%@",provisioningFile);
??? ??? ??? [FileManager removeItemAtPath:[NSString stringWithFormat:@"/vault/provisioning/%@",provisioningFile]
??? ??? ??? ??? ??? ??? ??? ??? ??? error:nil];
??? ??? }
這段代碼的功能是刪除/vault/provisioning下的所有文件,有興趣的可以親 自實(shí)驗(yàn)以下,確實(shí)可以刪除該文件夾下面的所有文件。但是有種情況不行,就是該文件夾下又存在文件夾的情況下,該方法removeitemAtPath就不 能刪除,也就是該方法只能刪除文件不能刪除目錄,所以在用的時(shí)候要格外小心,一定要認(rèn)真閱讀開發(fā)文檔。所以上面如果想要?jiǎng)h除該文件夾下面的所有文件及目 錄,就要寫成函數(shù)來遞歸調(diào)用。
void deleteAllAtPath(NSString *path)
{
??? ??? NSArray *aryProvsioning = [FileManager contentsOfDirectoryAtPath:path error:nil];
??????? if (aryProvsioning == nil)
??????????? return;
??? ??? for(NSString* provisioningFile in aryProvsioning)
??? ??? {
??? ??? ??? deleteAllAtPath(provisioningFile);
??????????? NSLog(@"delete file:%@",provisioningFile);
??? ??? ??? [FileManager removeItemAtPath:[NSString stringWithFormat:@"/vault/provisioning/%@",provisioningFile]
??? ??? ??? ??? ??? ??? ??? ??? ??? error:nil];
??? ??? }
}
??? 下面再來看一個(gè)讀寫文件的類NSFileHandle,其實(shí)它的實(shí)現(xiàn)就是調(diào)用c語言種文件流的操作。通過取得文件流的指針,然后定位指針的位置從而讀取出文件中的內(nèi)容,同樣在文件中寫入東西也是同樣的道理,下面來看一小短代碼。
??? NSFileHandle *TXTFileHandle;
??? NSString??? *szTXTFileTemp = @"111.txt";
??? TXTFileHandle = [NSFileHandle fileHandleForWritingAtPath:szTXTFileTemp];
??? //防止該文件不存在,如果不存在,新建該文件并寫入空數(shù)據(jù)。
??? if(!TXTFileHandle)
??? {
??? ??? [@"" writeToFile:szTXTFileTemp atomically:NO encoding:1 error:nil];
??? ??? TXTFileHandle = [NSFileHandle fileHandleForWritingAtPath:szTXTFileTemp];
??? }
??? [TXTFileHandle seekToEndOfFile];
??? char * conTemp = "mengtnt";
??? [TXTFileHandle? writeData:[NSData dataWithBytes:conTemp length:8];
??? [TXTFileHandle closeFile];
??? //下面是讀取
??? TXTFileHandle = [NSFileHandle fileHandleForReadingAtPath:szTXTFileTemp];
??? NSData *fileData = [TXTFileHandle readDataToEndOfFile];
??? NSlog(@"%@",[[NSString alloc] initWithData:fileData? encoding:NSUTF8StringEncoding]);
??? [TXTFileHandle closeFile];
? 以上就是cocoa編程中文件操作的常見用法,下面再看兩個(gè)類,雖說里面的方法都很簡單,但是不注意一些細(xì)節(jié)還是會(huì)出問題的。
??? NSThread類,開啟一個(gè)線程的方法在簡單不過了,[NSThread detachNewThreadSelector:@selector(StartThreadTest:) toTarget:self withObject:nil];其中selector就是你要調(diào)用的線程方法。
- (void)StartThreadTest:(id)idThread
{
??? NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
??? //一些UI事件以及其他事件處理
??? [pool release];
}
不知道大家注意了沒有,為什么線程中要加release pool那。特別是線程中有處理UI事件的時(shí)候一定要加上pool,否則你會(huì)發(fā)現(xiàn)應(yīng)用程序運(yùn)行異常的慢,甚至有的時(shí)候會(huì)crash掉。可能是線程的資源在 使用時(shí),很難判斷何時(shí)使用完畢,所以編譯器也就不方便自動(dòng)釋放這些資源,這樣就要手動(dòng)加上pool,使線程運(yùn)行到此處的時(shí)候釋放掉某些資源。究其深層的原 因,自己也是一知半解。這里僅僅是自己的一些想法,還望那位高手能指點(diǎn)下分析的是否正確。
??? 最后跟大家提以下NSTimer的用法,NSTimer說白了就是一個(gè)定時(shí)器,就是用來每隔一段時(shí)間運(yùn)行某段代碼,??? [NSTimer scheduledTimerWithTimeInterval:0.2
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? target:self
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? selector:@selector(DetectSN:)
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? userInfo:nil
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?repeats:YES];
當(dāng)你相停止timer的時(shí)候就調(diào)用invalide方法。需要注意的一點(diǎn)是當(dāng)NSTimer被設(shè)置無效的時(shí)候,要想使用這個(gè)timer對象,必須重新開辟一個(gè)NSTimer的對象。
??? 那么關(guān)于NSFoundation一些類的用法就先介紹到這里吧,這些都是自己平時(shí)整理一些資料,這些類都是比較容易用到,同時(shí)也容易出錯(cuò)的類。希望能給 大家一些幫助,同時(shí)在調(diào)試中也提高了自己的能力。以后我就來簡單的分享下自己cocoa編程中ApplicationKit框架的一些簡單用法,不過我一 直在UI設(shè)計(jì)方面存在先天不足,也希望在介紹ApplicationKit框架,各位老鳥看到我設(shè)計(jì)的一些UI的時(shí)候,能給點(diǎn)建設(shè)性的意見,以讓自己擺脫 這方面的苦惱。
轉(zhuǎn)載于:https://www.cnblogs.com/ligun123/archive/2011/08/23/2150417.html
總結(jié)
以上是生活随笔為你收集整理的Foundation框架中常用类的介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从Hadoop框架与MapReduce模
- 下一篇: win7下安装Oracle10g解决方案