Skip to content

Instantly share code, notes, and snippets.

@satoshin2071
Last active May 26, 2020 07:52
Show Gist options
  • Save satoshin2071/cc3a982b9b65dc9b8f20 to your computer and use it in GitHub Desktop.
Save satoshin2071/cc3a982b9b65dc9b8f20 to your computer and use it in GitHub Desktop.
CoreFoundation入門 基本クラス

#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
)

ソートできた。とりあえずここまで。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment