#CoreFoundation入門 Toll-free bridge
##概要 CoreFoundation入門 CFStringとその周辺の続き。
CoreFoundation入門 イントロで説明したFoundationとCoreFoundationの互換性を実現するToll-free bridgeの仕組みを確認していく。
##Tool-free bridgeとは
CocoaのオブジェクトをCoreFoundationから、そしてCoreFoundationのオブジェクトをCocoaから呼ぶ事ができる仕組み。
##NSStringとCFString
実はcocoaのFoundationの実装はCarbonのCoreFoudationでなされている。本当にFoundationのNSStringはCoreFoundationのCFStringということになるかを確認。
まずはclass-dumpを実行してNSCFStringで検索 (class-dumpなければbrew install class-dumpで入手できる)
% class-dump /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation > ./checkFoundation.h
@interface __NSCFString : __NSCFType
{
}
//メソッドは省略
@end
文字列を扱うクラスなのにインスタンス変数の定義がひとつもない、つまり NSCFStringは何かのラッパークラスであるということが推測として立てられる。
続いてNSStringとCFStringのインスタンスを作って中身を確認。
int main(int argc, const char * argv[]) {
NSString *str0 = @"string";
NSString *str1 = @"string";
CFStringRef str2 = CFSTR("string");
NSLog(@"str0 %p, str1 %p, str2 %p", str0, str1, str2);
return 0;
}
同じ文字列の3つのインスタンスは同じアドレスになるのでNSStringとCFStringの実体は同じだということがわかる。
##isaと_cfisa
上記のようにCoreFoundationのAPIにCocoaのオブジェクトが渡された時、これはCoreFoundationか?Cocoaか?を判別するかは __CFRuntimeBaseのcfisaとobjc_objectのisaポインタを使用している。
CFRuntime.h
typedef struct __CFRuntimeBase {
uintptr_t _cfisa;
uint8_t _cfinfo[4];
#if __LP64__
uint32_t _rc;
#endif
} CFRuntimeBase;
finderでobjc.hを検索
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
id型はobjc_object構造体のポインタだということ、objc_objectはClass型のisaをもっているということがわかる。
両方の先頭にisaポインタがあるので、Objective-Cから呼んだ時にメソッド呼び出しとしてisa先のクラスが処理をする。Cから呼ばれたときは無視する。なのでキャストし合っても問題なくアクセスできるという仕組みになっている模様。
cfisaの中身はどこで設定が行われているかについてを確認。昔はCFRuntime.cの_CFRuntimeCreateInstance関数内で行われていたようだが、現在はCFBase.cで行われていた。
CFBase.c
static void _CFAllocatorSetInstanceTypeIDAndIsa(struct __CFAllocator *memory) {
_CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID);
memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
}
引数で渡されたCFAllocatorからCFRuntimeBase、cfisaと辿り、__CFISAForTypeID関数を使用して値を設定していることがわかる。
_CFAllocatorSetInstanceTypeIDAndIsa以外の関数でも同様の処理が行われているで要確認。
__CFISAforTypeIDはCFInternal.hにて確認できる
CFInternal.h
#define __CFISAForTypeID(t) (0)
##Toll-free bridgeでのObjective-Cメソッド処理の流れ
NSStringのオブジェクト作成 イコール CFStringRefが作られ、_cfisaフィールドはNSCFString__を指す。
↓
上記のCFStringRefに対してメソッドを投げると_cfisaに設定されているクラスがこのメソッドを処理する
CoreFoundationの世界とObjective-Cの世界を行き来しながら処理を行っている。注目すべきところはどちらの世界からも扱うオブジェクトは一つだということ。なので余計な変換処理が発生しないところがToll-free bridgeの利点の一つ。
##CFType
CoreFoundationのオブジェクトにはToll-free bridgeで結ばれるオブジェクトが存在しないものもある。その場合の対応を行っているのがCFTypeというクラス。ドキュメントを確認。
CFType Reference
All other Core Foundation opaque types derive from CFType.
CFTypeを除くすべてのCoreFoundationのopaque型はCFTypeから派生している。
つまりCFTypeはルートクラスに近い存在ということになる。CFTypeの以下の関数はCoreFoundation全てのオブジェクトで使用できる。
Memory Management
- CFGetAllocator
- CFGetRetainCount
- CFMakeCollectable
- CFRelease
- CFRetain
Determining Equality
- CFEqual
Hashing
- CFHash
Miscellaneous Functions
- CFCopyDescription
- CFCopyTypeIDDescription
- CFGetTypeID
- CFShow
DataTypes
- CFHashCode
- CFTypeID
- CFTypeRef
CFTypeの詳細はCoreFoundation入門 メモリ管理で確認。