簡介
Core Foundation 是一組慨念源自OC基礎框架的編程接口,并使用c語言實現的庫.為了實現這個庫,Core Foundation用C語言實現一個限制對象模型.Core Foundation定義不透明類型來封裝數據和函數,之后就稱他們為"對象".
Core Foundation對象設計的編程接口具有易用性和可復用性.在普通層次下,Core Foundation有以下特性:
- 能夠在繁雜多樣的框架和庫中共享數據和代碼
- 使得在一定程度上獨立于操作系統成為可能
- 支持使用unicode字符串的國際化
- 提供一些API和其他有用的功能,包括一個插件架構,XML屬性列表等
Core Foundation使OS X上不同的框架和庫共享代碼與數據成為可能.應用,庫,框架讓你在平常C編程中,定義混合Core Foundation類型的接口;因此,它們可以計算數據--就像Core Foundation對象--通過這些接口設計算各自的數據.
Core Foundation在已確定的服務和Cocoa的Foundation框架之間提供"toll-free bridging"(無代價橋接). toll-free bridging能將函數參數中的Core Foundation對象替換成Cocoa對象或者反過來.
一些Core Foundation類型和函數是在不同操作系統上特定代碼實現的抽象. 使用這些API能更容易適配不同平臺.
date與number類型抽象了時間工具,并提供絕對時間和公歷時間的之間的轉換工具.它還抽象了數字值,并為這些內部表示不同的值提供的互轉工具.
Core Foundation給應用開發帶來其中一個主要的好處是支持國際化.通過框架中的字符串對象,Core Foundation使國際化在OS X與Cocoa上接口的編寫與實現變得更簡單,健壯和一致.這個特性的本質部分是一種類型--CFString, 代表一個16bit的Unicode字符數組. CFString對象能靈活地支持百萬字節的字符, 且使用一些足夠簡單的低層的接口就能計算字符數據.它達到了跟與之關聯的標準C字符串差不多的性能.
你應該閱讀這個文檔來了解Core Foundation之下的基本設計原則和Core Foundation對象跟Cocoa(Touch)對象之間的交互.
不透明類型
Core Foundation對象模型基于不透明類型,且支持封裝和多態函數.
基于不透明類型的對象的各個字段隱藏于客戶端,但是這些類型的函數能提供大多數字段值.Figure 1 描繪了不透明類型所隱藏的數據且僅展示其接口給客戶端.
Note: "Class"不是用來指向不透明類型的,盡管類和不透明類型概念上相似,可很多人可能被這個詞混淆.然而,Core Foundation文檔所指的類型是特定的,這些類型的數據承載實例就稱之為"對象"
Core Foundation有很多不透明類型,而且它們的名字說明了它們的預期用途.例如,CFString
是一個用來"展示"和操作Unicode字符數組的不透明類型(CF是Code Foundation的前綴). CFArray
是基于下標的泛型集合.一個不透明類型支持的函數,常量和其他次要的數據類型通常定義在其類型對應名字的頭文件中.例如CFArray.h
,CFArray
包含定義符號.

不透明類型的優點
部分情況下,一個不透明類型似乎要通過令人沮喪的結構內容直接存取來增加一些沒有必要的限制. 此外,似乎不透明的類型可能會影響項目性能相關的開銷.但是不透明類型的好處要大于這些表面的局限性.
不透明類型為底層功能的實現提供更好的靈活性和抽象性.通過隱藏結構字段的詳細信息,Core Foundation減少發在客戶端(Xcode)編碼時,字段詳情被更改后代碼出錯的幾率.此外,如果暴露不透明類型并允許優化,可能會造成困惑(譯注: 其他人可能看不懂其優化代碼,還不如封裝起來).例如CFString
"正式"代表UniChar
的16bit字符數組.然而, CFString
可能選擇儲存一個ASCII范圍內8bit數值的字符串.復制一個不可變的對象可能(經常發生)導致共同引用一個對象而不是內存中兩個獨立的對象.(查看Core Foundation內存管理編程指南).
繼續CFString
這個例子,使用一個不透明類型來儲存字符似乎太笨重.事實證明,并不是這樣的,CPU消耗的資源比使用簡單的C字符數組高不了多少,況且經常比他們低.另外,不透明并不一定說明這一個不透明類型從不提供直接訪問內容的機制.CFString
,對于它的實例,提供了CFStringGetCStringPtr
函數來直接訪問.
最后,你可以在一定的程度上自定義一些不透明類型.例如,集合類型允許為集合的每一個成員上為喚醒函數定義一個回調.集合類型允許調用函數時定義一個回調(譯注:callback,可以理解為函數指針),并讓每個集合成員調用.
對象引用
你可以通過引用來指向一個Core Foundation對象(不透明類型).對于頭文件的中的每一個不透明類型,你將會注意到一行或兩行相似的,類似下面的語句:
typedef const struct __CFArray * CFArrayRef;
typedef struct __CFArray * CFMutableArrayRef;
聲明這些指針指向(私有的)不可變和可變版本的結構.Core Foundation中許多函數的參數和返回值采用對象引用類型,而且從不使用typedef
私有結構的類型. 例如:
CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef array, CFStringRef separatorString);
查看 對象的種類獲取更多信息,可變的的還有其他種類的不透明對象.
每一個Core Foundation不透明類型給他們的對象定義一個唯一類型ID,如在CFArray
對象上的CFArrayRef
.類型ID是類型為CFTypeID
的整型,這個ID標識了一個Core Foundation所屬的不透明類型.在各種上下文中使用類型ID, 如在你操作各式各樣的容器時使用.Core Foundation提供一些編程性接口,用于獲取和計算類型ID的值.
重要:由于類型ID的值可以隨著版本的變化而變化,你的類型ID應該不能依賴已保存的或寫死的類型ID,也不應該被任何能觀察到的屬性賦值(例如賦給它一個簡單的整形:23333).
另外,Core Foundation定義了一個通用的對象引用(object-reference)類型, CFTypeRef
,類似其他面向對象語言的基(root)類.這個通用的引用作為一個多態函數的參數與返回值的占位符類型,可以指向任何Core Foundation對象.查看多態函數獲取更多關于這個課題的信息.查看Core Foundation的內存管理指南討論使用對象引用時內存管理的相關問題.
多態函數
Core Foundation提供一些多態函數,這些函數可以將任意Core Foundation對象作為參數和(有一個例子:CFRetain
)可以返回任意Core Foundation對象.這些參數和返回值的類型是CFTypeRef
,是一個通用的對象引用(object-reference)類型.CFType
是類似于其他面向對象語言中的根類,因為它的函數可以被其他所有對象復用.
你可以使用多態函數對所有的Core Foundation對象進行一些通用操作:
- 引用計數
CFType
提供幾個多態函數來計算和獲取對象的引用計數.查看Core Foundation的內存管理指南獲取更多的關于這些函數的信息. - 比較對象
CFEqual
函數能比較任何兩個Core Foundation對象(查看比較對象).等式成立的基本條件取決于同類型對象的比較.例如,如果比較兩個CFString
對象,該測試涉及逐個字符的比較. - 哈希對象
CFHash
函數返回一個唯一的能夠標識Core Foundation對象的哈希碼(查看比較對象).你可以把哈希碼當哈希表數據結構中的表地址.如果兩個對象相等(由CFEqual
函數決定),他們必須有相同的哈希值. - 核查對象
CFType
提供核查對象的函數,從而了解它們的內容以及他們"所屬"的類型.CFCopyDescription
函數返回一個描述該對象的字符串(更切確地說,是一個CFString
對象的引用).CFCopyTypeIDDescription
函數需要提供一個CFTypeID
參數而不是CFTypeRef
.這個函數返回一個描述標識一個不透明類型的類型ID的字符串引用.這些函數主要用來協助調試.查看核查對象獲取更多相關的函數.
你還可以通過CFGetTypeID
函數獲得不透明對象的類型ID,通過這個ID決定一個通用類型對象所屬的不透明類型,再將已知類型ID對應的值相比較.查看檢查對象獲取更多關于這個任務的信息.
對象的種類
不透明類型擁有多達3種基本種類,或者"口味".(譯注:這里為了跟之前的對象類型(object type)區分,故意使用種類或'口味').基于可擴展性和可編輯性的特點分為以下:
- 不可變和固定大小
- 可變和固定大小
- 可變和不固定大小
可變對象是可編輯的,意味著他們的內容可以修改.不可變對象不能編輯的;一旦創建之后就無法再改變.對不可變對象的任何修改都會導致一些(譯注:編譯器)錯誤.一個固定大小的可變對象有一個最大值來限制其大小的增長;就CFString
來說,一個CFString
可能是字符串中的字符個數,對于一個容器來說,其限制可能是元素的數量.
一些不透明類型,例如CFString
和CFArray
,可以創建所有三種口味
的對象.大部分不透明類型可以創建不可變的,固定大小的對象,至少有一個無限制的創建函數來創建無限制對象(如CFArrayCreate
).決定可變對象的可變大小或不可變大小的是CreateMutable
函數的容量(capacity
)參數和長度最大值(maximum-length
)參數;任何正整數都能生成對固定大小的對象,但是參數為0則生成一個可變大小對象.
使用帶有"Mutable"名字的類型指向可變對象,例如,CFMutableStringRef
.
命名約定
Core Foundation中主要編程接口的約定是使用不透明類型的名字中最密切相關的符號作為符號的前綴.對于函數,這個前綴不僅標識這該函數"屬于"那個類型,而且經常用來標識函數動作(action)的目標(target)對象的類型(type).(有一個例外是那些以k
作為前綴的常量).在頭文件中有一些例子:
/* from CFDictionary.h */
CF_EXPORT CFIndex CFDictionaryGetCountOfKey(CFDictionaryRef dict, const void *key);
/* from CFString.h */
typedef UInt32 CFStringEncoding;
/* from CFCharacterSet.h */
typedef enum {
kCFCharacterSetControl = 1,
kCFCharacterSetWhitespace,
kCFCharacterSetWhitespaceAndNewline,
kCFCharacterSetDecimalDigit,
kCFCharacterSetLetter,
kCFCharacterSetLowercaseLetter,
kCFCharacterSetUppercaseLetter,
kCFCharacterSetNonBase,
kCFCharacterSetDecomposable,
kCFCharacterSetAlphaNumeric,
kCFCharacterSetPunctuation,
kCFCharacterSetIllegal
} CFCharacterSetPredefinedSet;
除上述之外,Core Foundation中有一小部分編程接口約定是有關于不透明類型和內存管理的.
Get,Copy和Create之間有著很重大的區別,在于函數的返回值的命名.如果你使用Get函數,只是無法確定對象的生命周期.為了確保對象能夠持續存在,你可以持有(retain)它(使用
CFRetain
函數),或者在一些情況下,復制(copy)一份.如果你使用Copy或Create函數,你必須負責釋放對象(使用CFRelease
函數).更多詳情請查看Core Foundation內存管理指南-
部分Core Foundation對象有它們自己的命名約定,并以此加強通用操作的一致性.例如,集合(collection)將下列動詞嵌入函數名,已表示集合中的元素的特定操作.
-
Add
意味'如果存在就添加,如果存在就不做任何事'(針對某一個集合實例) -
Replace
意味'如果存在就替換,如果不存在就不做任何事' -
Set
意味'如果不存在就添加,如果存在就替換' -
Remove
意味'如果存在就刪除,如果不存在就不做任何事'
-
CFIndex
類型用于下標(index),計數(count),長度(length),和大小(size),并作為函數的參數或者返回值.這個類型(整形)的值(當前是32位),可以隨著處理器地址大小的增長而增長.在指針大小不同的架構上,如果是64位處理器,CFIndex可能是64位,這取決于int
的大小.在Core Foundation參數中使用相同類型CFIndex
的變量進行交互,可以確保您的代碼有更高的源碼兼容性.一些Core Foundation頭文件似乎定義不透明類型,但實際上卻包含便利函數而不是關聯一些特定的類型.恰當的例子是
CFPropertyList.h
.CFPropertyList
是下列屬性列表類型中任意一個類型的占位符類型:CFString
,CFDate
,CFBoolean
,CFNumber
,CFDate
,CFArray
和CFDictionary
.除非特殊說明,否則所有傳遞引用參數并打算返回值都可以接受
NULL
.這表明調用者不需要關心函數的返回值.
其他類型
Core Foundation定義若干個數據類型,并在函數中使用.這些類型存在的目的是抽象原始值.這個原始值可能隨處理器地址空間改變而改變.例如CFIndex
類型,應用于下標(index), 計數(count),長度(length),和大小(size)參數.CFOptionFlags
類則用于位字段參數,CFHashCode
類型包含從CFHash
函數和已確定的哈希回調中返回的哈希結果.
其他基本類型用于傳入函數和函數返回的比較值與范圍值.CFRange
是一個指定線性隊列的任意一部分的結構,從字符串中的數組到集合中的元素.對于比較函數,CFComparisonResult
類型定義枚舉常量來代表適當的返回值(等于,小于,大于).部分Core Foundation函數傳入一個回調到比較函數中去;如果你需要自定義比較操作,函數必須符合CFComparatorFunction
中指定的類型(譯注:函數的參數必須與(const void *val1, const void *val2, void *context)相同).
重要: 只要其值是整形值,那么其類型一定是Core Foundation類型,特別是
CFIndex
和CFTypeID
,可以隨著處理器尋址大小的增長而增長.在Core Foundation參數中使用相同類型CFIndex
的變量進行交互,可以讓確保您的代碼有更高的源碼兼容性.
Core Foundation中體統的其他不透明類型在其他主題中討論.
比較對象
你可用CFEqual
函數來比較兩個Core Foundation對象.如果兩個對象在本質上是相等的,函數將返回一個boolean
類型的true
值."本質上"相等取決于相同類型的對象的比較.當你比較兩個CFString
對象,不管他們的編碼和是否可變,當他們逐個字符完全匹配時, Core Foundation則認為他們本質上相等.兩個CFArray
對象比較,當它們有相同數量的元素和數組中每一個元素對象與對應數組中的元素本質上相等,這時會認為他們本質上相等.很明顯,比較對象必須是相同類型(不管可變或不可變)才會認為是相等的.
下面代碼片段給你展示了可能使用CFEqual
函數比較一個常量與傳入參數是否相等.
Listing 1 比較Core Foundation對象
void stringTest(CFStringRef myString) {
Boolean equal = CFEqual(myString, CFSTR(“Kalamazoo”));
if (!equal) {
printf(“They’re not equal!");
}
else {
printf(“They’re equal!”):
}
}
核查對象
Core Foundation對象的主要特征是它們都基于一個不透明(或私有)類型;可能因此難以直接核查對象的內部數據.然而,基礎服務提供了兩個函數來檢查Core Foundation對象.這些函數返回對象及對象類型的描述信息.
為了找出Core Foundation對象的內容,調用CFCopyDescription
函數并傳進其對象.然后打印所引用的字符串對象所"包含"的字符序列.
Listing 1 使用CFCopyDescription
void describe255(CFTypeRef tested) {
char buffer[256];
CFIndex got;
CFStringRef description = CFCopyDescription(tested);
CFStringGetBytes(description,
CFRangeMake(0, CFStringGetLength(description)),
CFStringGetSystemEncoding(), '?', TRUE, buffer, 255, &got);
buffer[got] = (char)0;
fprintf(stdout, "%s", buffer);
CFRelease(description);
}
這個例子顯示了一種打印描述信息(description)的途徑.你不應該使用CFStringGetBytes
,而是使用CFString
函數來獲取真正的字符串.
為了確定一個"未知"對象的類型,用CFGetTypeID
函數取得它的類型ID,將值與已知的類型ID進行比較,直到匹配.可以使用CFGetTypeID
獲取一個對象的類型ID.每一個不透明類型還定義了一個CFTypeGetTypeID
表格的函數(例如CFArrayGetTypeID
);這個函數返回給定類型的類型ID.在此之前,你可以測試一下一個CFType
對象是否是指定不透明類型的成員.
CFTypeID type = CFGetTypeID(anObject);
if (CFArrayGetTypeID() == type)
printf(“anObject is an array.”);
else
printf(“anObject is NOT an array.”);
為了打印Core Foundation對象的類型在調試狀態下的相關信息.使用CFGetTypeID
函數來獲取這個類型ID,然后通過這個值傳入CFCopyTypeIDDescription
函數:
/* aCFObject is any Core Foundation object */
CFStringRef descrip = CFCopyTypeIDDescription(CFGetTypeID(aCFObject));
注意: 字符串基礎功能中包含兩個函數:
CFShow
和CFShowStr
,都聲明在CFString.h
頭文件中.在調試模式下,你可以調用它們打印Core Foundation的描述.
重要:
CFCopyDescription
和CFCopyTypeIDDescription
只在調試模式下使用.不要創建任何依賴它們的代碼,因為描述信息與他們的格式隨時改變.
無代價橋接類型
在Core Foundation框架與Foundation框架中有若干可相互轉換的數據類型.可相互裝換的數據類型也被稱為無代價橋接(toll-free bridged)數據類型.這意味著你可以使用相同的數據結構作為參數傳進Core Foundation調用的函數和作為一個Objective-C消息發送的接收器.例如,NSLocale
(查看NSLocale Class Reference), 與之對應的Core Foundation的CFLocal
(查看CFLocale)是可相互轉換的.
不是所有的數據類型都是無代價橋接的,甚至通過他們的名字可能猜得出他們是有代價橋接的.例如NSRunLoop
轉換到CFRunLoop
不是無代價橋接,NSBundle
轉換至CFBundle
不是無代價橋接.NSDateFormate
轉換到CFDateFormatter
也不是.table 1提供了一張提供的無條件橋接的表.
注意: 在你使用corefoundation的集合時,如果安裝(install)一個自定義回調(call back),包括
NULL
回調.從Objective-C訪問時,該自定義回調的內存管理的行為是沒有定義的.
強制類型轉換和對象生命期的語義(Casting and Object Lifetime Semantics)
通過無條件橋接,當你在一個方法中,看到有些參數,例如NSLocale *
參數,可以傳進一個CFLocaleRef
;在函數看到CFLocaleRef
參數,你可以傳一個NSLocale
實例.不過你必須為編譯器提供其他信息: 首先, 將一個類型強制轉換(cast)為其他類型;另外,你可能還要指示出對象的聲明期語義.
編譯器理解Objective-C方法返回的Core Foundation類型和遵循過去Cocoa命名約定(查看高級內存管理編程指南).例如,編譯器知道在iOS中,通過UIColor
本身并沒有CGColor
方法來返回一個CGColor
. 你必須使用適當的強制類型轉換(cast),就像下面所展示的:
NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
[colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
編譯器不會自動管理Core Foundation對象的生命期.選擇強制類型轉換(cast)(在objc/runtime.h
中定義)和Core Foundation風格的宏(在NSObject.h
中定義)其中一個,告訴編譯器關于對象的持有者.
__bridge
將一個指向Objective-C與Core Foundation兩者之一的指針相互轉換,沒有轉換持有權.__bridge_retained
或CFBridgingRetain
強制類型轉換(cast)指向Objective-C的指針為Core Foundation指針并把持有權轉給你.
你負責調用CFRelease
或相關函數來放棄對象的持有權.-
__bridge_transfer
或CFBridgingRelease
移動一個非Objective-C指針到Objective-C,并且將對象持有權交給ARC.
ARC 有負責放棄對象的持有權.
上述看起來就像下面這個例子:NSLocale *gbNSLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"]; CFLocaleRef gbCFLocale = (__bridge CFLocaleRef)gbNSLocale; CFStringRef cfIdentifier = CFLocaleGetIdentifier(gbCFLocale); NSLog(@"cfIdentifier: %@", (__bridge NSString *)cfIdentifier); // Logs: "cfIdentifier: en_GB" CFLocaleRef myCFLocale = CFLocaleCopyCurrent(); NSLocale *myNSLocale = (NSLocale *)CFBridgingRelease(myCFLocale); NSString *nsIdentifier = [myNSLocale localeIdentifier]; CFShow((CFStringRef)[@"nsIdentifier: " stringByAppendingString:nsIdentifier]);
下一個例子展示Core Foundation內存管理函數的用法.這些函數由Core Foundation內存管理規則主宰:
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGFloat locations[2] = {0.0, 1.0};
NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
[colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
CGColorSpaceRelease(colorSpace); // Release owned Core Foundation object.
CGPoint startPoint = CGPointMake(0.0, 0.0);
CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient); // Release owned Core Foundation object.
}
無代價橋接類型
table 1 提供一個可在Core Foundation和Foundation之間相互裝換的數據類型的列表.對于每一對,表中來列舉了它們之間無代價橋接變得有效時OS X的版本.
Table 1 在Core Foundation和Foundation之間相互裝換的數據類型
Core Foundation type | Foundation Class | Availability |
---|---|---|
CFArrayRef | NSArray | OS X v10.0 |
CFAttributedStringRef | NSAttributedString | OS X v10.4 |
CFCalendarRef | NSCalendar | OS X v10.4 |
CFCharacterSetRef | NSCharacterSet | OS X v10.0 |
CFDataRef | NSData | OS X v10.0 |
CFDateRef | NSDate | OS X v10.0 |
CFDictionaryRef | NSDictionary | OS X v10.5 |
CFErrorRef | NSError | OS X v10.5 |
NSLocale | NSLocale | OS X v10.4 |
CFMutableArrayRef | NSMutableArray | OS X v10.0 |
CFMutableAttributedStringRef | NSMutableAttributedString | OS X v10.4 |
CFMutableCharacterSetRef | NSMutableCharacterSet | OS X v10.0 |
CFMutableDataRef | NSMutableData | OS X v10.0 |
CFMutableDictionaryRef | NSMutableDictionary | OS X v10.0 |
CFMutableSetRef | NSMutableSet | OS X v10.0 |
CFMutableStringRef | NSMutableString | OS X v10.0 |
CFNumberRef | NSNumber | OS X v10.0 |
CFReadStreamRef | NSInputStream | OS X v10.0 |
CFRunLoopTimerRef | NSTimer | OS X v10.0 |
CFSetRef | NSSet | OS X v10.0 |
CFStringRef | NSString | OS X v10.0 |
CFTimeZoneRef | NSTimeZone | OS X v10.0 |
CFURLRef | NSURL | OS X v10.0 |
CFWriteStreamRef | NSOutputStream | OS X v10.0 |