#CoreFoundation入門 基本クラス
##概要
Core Foundationで頻出するドキュメントにて「Derived from CFPropertyList」となっている以下の基本クラスを確認。
CFData, CFString, CFArray, CFDictionary, CFDate, CFNumber(CFBoolean)
※CFNumber、CFDate以外は上記のImutable型に対してそれぞれMutablel型が用意されている。
##CFString
文字を扱うクラス。retain/releaseが必須でなくオブジェクトはアプリケーション終了時に解放される。
まずはCFSTRのマクロを定義している箇所を確認。CFString.hの 172行目くらい
#ifdef __CONSTANT_CFSTRINGS__
#define CFSTR(cStr) ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr ""))
#else
#define CFSTR(cStr) __CFStringMakeConstantString("" cStr "")
#endif
_builtin は関数をビルトイン関数化する拡張命令。ビルトイン関数化するとCの標準ライブラリと同等の扱いになる。最適化、.hをインクルードしなくても使えるようになる。
__CFStringMakeConstantString ("" cStr "")
↓
printf("A" "yes" "A");
↓
AyesA と等価になる
↓
こんな書き方もできる。
printf("A"
"yes"
"A"
"\n");
つぎにCFShowStrを確認。CFShowStrはCFStringの詳細なログ出力を行うデバッグ用。 CFString.hの874行目あたり。
/*
Use CFShowStr() to printf detailed info about a CFString
*/
...
CF_EXPORT
void CFShowStr(CFStringRef str);
CFShowStr(CFSTR("yes"));
実行結果
Length 3
IsEightBit 1
HasLengthByte 0
HasNullByte 1
InlineContents 0
Allocator SystemDefault
Mutable 0
Contents 0x100000f8f
※ デバッグ用なので、このメソッドが返す結果に依存したコードは絶対に書かない事。
##コレクションクラス
CoreFoundationには以下のコレクションクラスがある。
CFArray,CFSet,CFDictionary,CFBag,CFTree。
NSArrayがオブジェクトのみを扱うのに対してCFArray等のCoreFoudationのコレクションクラスはオブジェクト以外の独自のデータ型,プリミティブ型を持つ事ができる。
Collections Programming Topics for Core Foundationより抜粋 1行目後半から。
A collection can contain other Core Foundation objects, custom data structures, and primitive data values.
具体的にどのような実装になっているかをCFArray.cの最後のindexの値を返すCFArrayGetLastIndexOfValueで確認
CFIndex CFArrayGetLastIndexOfValue(CFArrayRef array, CFRange range, const void *value) {
CFIndex idx;
__CFGenericValidateType(array, __kCFArrayTypeID);
__CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
CHECK_FOR_MUTATION(array);
const CFArrayCallBacks *cb = CF_IS_OBJC(CFArrayGetTypeID(), array) ? &kCFTypeArrayCallBacks : __CFArrayGetCallBacks(array);
for (idx = range.length; idx--;) {
const void *item = CFArrayGetValueAtIndex(array, range.location + idx);
if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item)))
return idx + range.location;
}
return kCFNotFound;
}
第三引数の「const void *value」に注目。CFTypeのオブジェクトのみ扱うなら「const CFTypeRef」となるはずなのでオブジェクト以外も持てることがわかる。
→ Toll-Free Bridge可能なのでプリミティブ型が扱えないNSArrayにする際などに注意が必要
というわけで実際に使ってみる
int main(int argc, const char * argv[]) {
const void *values[] = {CFSTR("A"),CFSTR("B"),CFSTR("C")};
CFArrayRef array = CFArrayCreate(kCFAllocatorDefault, values, 3, NULL);
CFShow(array);
CFRelease(array);
return 0;
}
// 実行結果
<CFArray 0x100201be0 [0x7fff7526af00]>{type = immutable, count = 3, values = (
0 : <0x100001058>
1 : <0x100001078>
2 : <0x100001098>
)}
アドレスが表示されてしまう。CFArrayCreateの定義をドキュメントで確認
CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
第四引数のcallBacksについてのドキュメントより抜粋
A pointer to a CFArrayCallBacks structure initialized with the callbacks for the array to use on each value in the collection.
↓
callBacksはコレクションのそれぞれの値に対して使用されるコールバック関数で初期化されたCFArrayCallBacksのポインタ
This value may be NULL, which is treated as if a valid structure of version 0 with all fields NULL had been passed in.
↓
NULLを渡すと、version = 0, それ以外はNULLの構造体を渡したとみなされる。
If the collection contains only CFType objects, then pass a pointer to kCFTypeArrayCallBacks (&kCFTypeArrayCallBacks) to use the default callback functions.
↓
コレクションがCFTypeオブジェクトのみを持つときはkCFTypeArrayCallBacksのポインタを渡すとデフォルトのコールバック関数が使われる。
今回はCFTypeオブジェクトのみの配列なのでNULLではなくkCFTypeArrayCallBacksのポインタを返してみるように修正
int main(int argc, const char * argv[]) {
const void *values[] = {CFSTR("A"),CFSTR("B"),CFSTR("C")};
CFArrayRef array = CFArrayCreate(kCFAllocatorDefault, values, 3, &kCFTypeArrayCallBacks);
CFShow(array);
CFRelease(array);
return 0;
}
実行結果
(
A,
B,
C
)
Toll-Free Bridgeするなら
NSLog(@"%@",(__bridge NSArray*)array);
CoreFoundationSample[1262:303] (
A,
B,
C
)
##CFMutableArray
つづいてCFMutableArrayの動作確認
int main(int argc, const char * argv[]) {
CFMutableArrayRef array;
array = CFArrayCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
CFArrayAppendValue(array, CFSTR("A"));
CFArrayAppendValue(array, CFSTR("B"));
CFArrayAppendValue(array, CFSTR("C"));
CFShow(CFSTR("print all"));
CFShow(array);
CFShow(CFSTR("Remove Value At index 1"));
CFArrayRemoveValueAtIndex(array, 1);
CFShow(array);
CFShow(CFSTR("Remove All Value"));
CFArrayRemoveAllValues(array);
CFShow(array);
return 0;
}
// 実行結果
print all
(
A,
B,
C
)
Remove Value At index1
(
A,
C
)
Remove All Value
(
)
##CFNumber
つづいてCFNumberの動作確認
int main(int argc, const char * argv[]) {
printf("CFIndex value \n");
CFIndex value = 123;
CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &value);
printf(" number type => %ld \n", CFNumberGetType(number));
printf(" byteSize => %ld \n", CFNumberGetByteSize(number));
printf(" isFloatType => %d \n", CFNumberIsFloatType(number));
NSInteger getValue;
CFNumberGetValue(number, kCFNumberCFIndexType, &getValue);
printf(" getValue => %ld \n",getValue);
printf("Float value \n");
float floatValue = 0.123;
CFNumberRef floatNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &floatValue);
printf(" number type => %ld \n", CFNumberGetType(floatNumber));
printf(" byteSize => %ld \n", CFNumberGetByteSize(floatNumber));
printf(" isFloatType => %d \n", CFNumberIsFloatType(floatNumber));
float getFloatValue;
CFNumberGetValue(floatNumber, kCFNumberFloatType, &getFloatValue);
printf(" getValue => %f \n",getFloatValue);
CFRelease(number);
CFRelease(floatNumber);
return 0;
}
// 実行結果
CFIndex value
number type => 4
byteSize => 8
isFloatType => 0
getValue => 123
Float value
number type => 5
byteSize => 4
isFloatType => 1
getValue => 0.123000
##CFBoolean
つづいてCFBooleanの動作確認。別にCFNumberを継承しているわけではない。
int main(int argc, const char * argv[]) {
CFShow(kCFBooleanTrue);
CFShow(kCFBooleanFalse);
printf("true => %d \n",CFBooleanGetValue(kCFBooleanTrue));
printf("false => %d \n",CFBooleanGetValue(kCFBooleanFalse));
printf("CFBooleanGetTypeID = %ld \n",CFBooleanGetTypeID());
return 0;
}
// 実行結果
<CFBoolean 0x7fff7526b7f0 [0x7fff7526af00]>{value = true}
<CFBoolean 0x7fff7526b800 [0x7fff7526af00]>{value = false}
true => 1
false => 0
CFBooleanGetTypeID = 21
##比較メソッド
###CFNumberCompareメソッド
int main(int argc, const char * argv[]) {
CFIndex one = 1, two = 2;
CFNumberRef number1 = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &one);
CFNumberRef number2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &two);
CFComparisonResult compResult = CFNumberCompare(number1, number2, NULL);
printf("compResult %ld \n",compResult);
compResult = CFNumberCompare(number2, number2, NULL);
printf("compResult %ld \n",compResult);
compResult = CFNumberCompare(number2, number1, NULL);
printf("compResult %ld \n",compResult);
return 0;
}
// 実行結果
compResult -1
compResult 0
compResult 1
###CFStringCompareメソッド
int main(int argc, const char * argv[]) {
printf("a : b %ld \n", CFStringCompare(CFSTR("a"), CFSTR("b"), 0));
printf("b : b %ld \n", CFStringCompare(CFSTR("b"), CFSTR("b"), 0));
printf("b : a %ld \n", CFStringCompare(CFSTR("b"), CFSTR("a"), 0));
printf("A : a %ld \n", CFStringCompare(CFSTR("A"), CFSTR("a"), kCFCompareCaseInsensitive));
return 0;
}
// 実行結果
a : b -1
b : b 0
b : a 1
A : a 0
###CFBooleanの比較
== でok
printf("kCFBooleanTrue : kCFBooleanFalse %d \n", kCFBooleanTrue == kCFBooleanFalse);
printf("kCFBooleanFalse : kCFBooleanFalse %d\n", kCFBooleanFalse == kCFBooleanFalse);
##CFTypeの準共通のメソッド
いくつかメソッドを確認すると明確な命名規則によって作られている関数が確認できる
-
CFArray
-
CFArrayCreate
-
CFArrayCreateCopy
-
CFArrayCreateMutable
-
CFArrayCreateMutableCopy
-
CFString
-
CFStringCreate
-
CFStringCreateCopy
-
CFStringCreateMutable
-
CFStringCreateMutableCopy
CoreFoundationのMutable型
Immutable | Mutable |
---|---|
CFArray | CFMutableArray |
CFAttributeString | CFMutableAttributeString |
CFBag | CFMutableBag |
CFBitVector | CFMutableBitVector |
CFCharcterSet | CFMutableCharcterSet |
CFData | CFMutableData |
CFDictionary | CFMutableDictionary |
CFSet | CFMutableSet |
CFString | CFMutableString |
##Compareメソッド
大小関係のあるクラス(CFString,CFNumber,CFDate)はClassName+Compareという比較メソッドをもっている。(返すのはCFComparisonResult)
- CFComparisonResult CFStringCompare(CFStringRef theString1, CFStringRef theString2, CFStringCompareFlags compareOptions);
- CFComparisonResult CFNumberCompare(CFNumberRef number, CFNumberRef otherNumber, void *context);
- CFComparisonResult CFDateCompare(CFDateRef theDate, CFDateRef otherDate, void *context);
というわけでCFMutableArrayにCFNumberをいれてソートしてみる。
int main(int argc, const char * argv[]) {
CFMutableArrayRef array;
array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFIndex one = 1, two = 2, three = 3;
CFNumberRef number1, number2, number3;
number1 = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &one);
number2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &two);
number3 = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &three);
// バラバラな順調で配列に追加
CFArrayAppendValue(array, number2);
CFArrayAppendValue(array, number3);
CFArrayAppendValue(array, number1);
CFRelease(number1);
CFRelease(number2);
CFRelease(number3);
CFShow(CFSTR("print all"));
CFShow(array);
CFArraySortValues(array, CFRangeMake(0, CFArrayGetCount(array)), (CFComparatorFunction)CFNumberCompare, NULL);
CFShow(CFSTR("sorted array"));
CFShow(array);
CFRelease(array);
return 0;
}
// 実行結果
print all
(
2,
3,
1
)
sorted array
(
1,
2,
3
)
ソートできた。とりあえずここまで。