Я пытаюсь реализовать метод countByEnumeratingWithState:objects:count:
из протокола NSFastEnumeration в пользовательском классе.NSFastEnumeration object casting in ARC
До сих пор я выполнял итерацию через мои объекты правильно, но возвращаемые объекты не являются объектами 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 *)
, кажется, бросается в указатель типа void с __bridge, используемым для соединения мира obj-c с миром CF. Согласно llvm docs, для __bridge
:
There is no transfer of ownership, and ARC inserts no retain operations
Является ли это правильно?
С моей точки зрения __NSCFConstantString - это основной базовый эквивалент NSString. Я также понимаю, что с ARC вам нужно перейти от объектов Objective-C к эквивалентам CoreFoundation, потому что ARC не знает, как управлять памятью последнего.
Как я могу заставить это работать так, чтобы объекты в моем цикле «for..in» имели оригинальный тип?
Также обратите внимание, что в этом случае я добавляю NSStrings в свою коллекцию, но теоретически он должен поддерживать любой объект.
UPDATE
ответ Роба на правильном пути, но проверить эту теорию я изменил цикл для этого:
for (id object in myCustomCollection) {
NSString *stringObject = (NSString *)object;
NSLog(@"String %@ length: %d", stringObject, [stringObject length]);
}
В теории, которые должны работать, так как объекты эквивалентны, но она падает с этой ошибкой:
+[__NSCFConstantString length]: unrecognized selector sent to class
это выглядит почти как объекты, возвращаемые в for
цикл - это классы, а не экземпляры. Что-то еще может быть здесь не так ... Любые мысли об этом?
UPDATE 2: РЕШЕНИЕ
Это так просто, как это: (благодаря CodaFi
state->itemsPtr = &someObject;
Вы правы! Глупая ошибка с моей стороны.Похоже, мне нужно пересмотреть синтаксис указателя на C. Как вы уже сказали, это немного случайность, что это сработало так, как это дало базовое структурное представление объектов. – nebs
С '&' вы можете избавиться от обоих этих ужасных бросков. – CodaFi
Блестящий! Не могли бы вы кратко объяснить, почему это работает? itemsPtr определяется как это в struct: 'id __unsafe_unretained * itemsPtr'. Из моего понимания 'id' означает« указатель на что-то ». Поэтому, если мы игнорируем часть '__unsafe_unretained', у нас есть' id * 'как тип, что означает« указатель на указатель на что-то »правильно? Тогда '&' означает 'адрес'. Поэтому, когда я делаю & someObject, он возвращает мне целое число, являющееся адресом памяти объекта. Я не уверен, что понимаю, почему & myObject можно назначить 'id *'. Указывает ли itemsPtr на другой указатель, который теперь содержит адрес myObject? – nebs