カスタム クラスでNSFastEnumerationcountByEnumeratingWithState:objects:count:
プロトコルのメソッドを実装しようとしています。
これまでのところ、オブジェクトを正しく反復処理していますが、返されるオブジェクトは Objective-C オブジェクトではなく、コアとなる基盤の同等物です。
state->itemsPtr を設定するコードの一部を次に示します。
MyCustomCollection.m
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state
objects: (id __unsafe_unretained *)buffer
count: (NSUInteger)bufferSize {
// ... skip details ...
NSLog(@"Object inside method: %@", someObject);
state->itemsPtr = (__unsafe_unretained id *)(__bridge void *)someObject;
// ... skip details ...
}
次に、このように「for..in」ループを別の場所で呼び出します
SomeOtherClass.m
MyCustomCollection *myCustomCollection = [MyCustomCollection new];
[myCustomCollection addObject:@"foo"];
for (id object in myCustomCollection) {
NSLog(@"Object in loop: %@", object);
}
コンソール出力は次のとおりです。
Object inside method: foo
Object in loop: __NSCFConstantString
ご覧のとおり、NSFastEnumeration プロトコル メソッド内では、オブジェクトは正常に出力されますが、キャストされるとすぐにid __unsafe_unretained *
、元の Objective-C 対応クラスが失われます。
正直なところ(__unsafe_unretained id *)(__bridge void *)
、この場合のキャスティングがどのように機能するかはよくわかりません。は(__unsafe_unretained id *)
、適切なタイプの itemsPtr のニーズに一致するようにキャストされているようです。は(__bridge void *)
、obj-c ワールドを CF ワールドにブリッジするために使用される __bridge を使用して、タイプ void のポインターにキャストするようです。llvm docsに従って、次の場合__bridge
:
所有権の譲渡はなく、ARC は保持操作を挿入しません。
あれは正しいですか?
私の理解では、__NSCFConstantString は NSString に相当するコア基盤にすぎません。また、ARC では、Objective-C オブジェクトから同等の CoreFoundation オブジェクトにブリッジする必要があることも理解しています。これは、ARC が後者のメモリを管理する方法を知らないためです。
「for..in」ループ内のオブジェクトが元のタイプになるようにするにはどうすればよいですか?
また、この場合、コレクションに NSStrings を追加していますが、理論的にはすべてのオブジェクトをサポートする必要があることに注意してください。
アップデート
ロブの答えは正しい軌道に乗っていますが、その理論をテストするために、for ループを次のように変更しました。
for (id object in myCustomCollection) {
NSString *stringObject = (NSString *)object;
NSLog(@"String %@ length: %d", stringObject, [stringObject length]);
}
理論的には、オブジェクトは同等であるため機能するはずですが、次のエラーでクラッシュします。
+[__NSCFConstantString length]: unrecognized selector sent to class
ループで返されるオブジェクトは、for
インスタンスではなくクラスのように見えます。ここで何か他のことが間違っているかもしれません...これについて何か考えはありますか?
更新 2: ソリューション
次のように簡単です: (CodaFi のおかげで
state->itemsPtr = &someObject;