我正在尝试在自定义类的NSFastEnumeration协议中实现countByEnumeratingWithState: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 *)
强制转换为匹配itemPtr需要的正确类型。 (__bridge void *)
似乎转换为void类型的指针,__ bridge用于将obj-c世界桥接到CF世界。根据{{3}},__bridge
:
没有所有权转让,ARC不会保留任何保留操作
这是对的吗?
从我的理解__NSCFConstantString只是NSString的核心基础。我也理解,使用ARC,你需要从Objective-C对象桥接到CoreFoundation等价物,因为ARC不知道如何管理后者的内存。
我怎样才能使这个'for..in'循环中的对象属于原始类型?
另请注意,在这种情况下,我将NSStrings添加到我的集合中,但理论上它应该支持任何对象。
更新
Rob的回答是正确的,但为了测试这个理论,我将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;
答案 0 :(得分:3)
您输错了someObject
。你的意思是:
<击>
state-&gt; itemsPtr =(__ innafe_unretained id *)(__ bridge void *)&amp; someObject;
击>
(让我们摆脱那些可怕的演员阵容)
state->itemsPtr = &someObject;
如果没有address-of,则将您的变量推入第一个指针,该指针在循环中被取消引用。当它被解除引用时(基本上是*id
),你得到了底层的objc_object的isa
类指针而不是一个对象。这就是为什么调试器在枚举器调用中打印字符串的值,以及循环内对象的类,以及为什么向结果指针发送消息会引发异常。
答案 1 :(得分:1)
你的代码很好。您的调试输出显示了实现细节。
NSString
is toll-free-bridged with CFString
.这意味着您可以将任何NSString
视为CFString
,反之亦然,只需将指针投射到其他类型即可。
事实上,编译时常量字符串是__NSCFConstantString
类型的实例,这就是你所看到的。
如果您将@"hello"
放入源代码中,编译器会将其视为NSString *
并将其编译为__NSCFConstantString
的实例。
如果您将CFSTR("hello")
放入源代码中,编译器会将其视为CFStringRef
并将其编译为__NSCFConstantString
的实例。
在运行时,这些对象在内存中没有区别,即使您使用不同的语法在源代码中创建它们。