2

countByEnumeratingWithState:objects:count: 메서드를 사용자 정의 클래스의 NSFastEnumeration 프로토콜에서 구현하려고합니다.ARC의 NSFastEnumeration 객체 캐스팅

지금까지 내가 내 객체를 올바르게 반복하지만, 반환되는 객체는 Objective-C 객체가 아니라 오히려 핵심 기초 동등 물입니다. 여기

을 설정하는 코드의 일부 년대 상태 -> itemsPtr :

- (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을'다른 곳에서 전화

MyCustomCollection.m

SomeOtherClass.m

MyCustomCollection *myCustomCollection = [MyCustomCollection new]; 
[myCustomCollection addObject:@"foo"]; 
for (id object in myCustomCollection) { 
    NSLog(@"Object in loop: %@", object); 
} 

콘솔 출력은 다음과 같습니다 당신이 볼 수 있듯이 개체 인쇄 미세 NSFastEnumeration 프로토콜 메서드 내

Object inside method: foo 
Object in loop: __NSCFConstantString 

는하지만, 즉시이 id __unsafe_unretained *로 캐스팅됩니다 나는이 클래스를 해당 원래 목표 - C를 잃게됩니다.

솔직히 말해서이 경우에 (__unsafe_unretained id *)(__bridge void *) 캐스팅이 어떻게 작동하는지 잘 모르겠습니다. (__unsafe_unretained id *)은 필요한 유형 항목과 일치하도록 캐스팅 된 것처럼 보입니다. (__bridge void *)은 obj-c 세계를 CF 세계에 연결하는 데 사용되는 __bridge를 사용하여 void 유형의 포인터로 캐스팅 된 것처럼 보입니다. __bridge에 대한 llvm docs, 당 :

There is no transfer of ownership, and ARC inserts no retain operations

올바른인가요?

제 생각에 __NSCFConstantString은 NSString의 핵심 기초입니다. 또한 ARC는 Objective-C 객체에서 CoreFoundation 객체로 연결해야한다는 것을 알고 있습니다. 왜냐하면 ARC는 후자의 메모리를 관리하는 방법을 모르기 때문입니다.

어떻게하면 'for..in'루프의 객체가 원래 유형이되도록 할 수 있습니까?

또한이 경우에는 NSString을 내 컬렉션에 추가하지만 이론적으로는 모든 개체를 지원해야합니다.

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 반환 : 그것은이 오류와 충돌 루프는 클래스가 아니라 인스턴스입니다. 여기 뭔가 잘못되었을 수도 있습니다 ... 이것에 대한 어떤 생각?.

업데이트 2 : 솔루션은

그것은이처럼 간단합니다 CodaFi

state->itemsPtr = &someObject; 

답변

3

someObject을 잘못 전송했습니다. 당신이 의미하는 것은 :

state-> itemsPtr = (__unsafe_unretained id *) (__ bridge void *) & someObject;

당신의 변수는 루프에서 역 참조되는 첫 번째 포인터로 밀려되면, 주소의없이

state->itemsPtr = &someObject; 

(의이뿐만 아니라 그 끔찍한 캐스트를 제거하자). 역 참조 (기본적으로 *id) 일 때 객체가 아닌 기본 objc_object의 isa 클래스 포인터를 얻습니다. 그래서 디버거는 문자열의 값을 열거 자 호출 내에서 출력하고 루프 내부의 객체 클래스를 출력하고 결과 포인터에 메시지를 보내면 예외가 발생합니다.

+0

당신 말이 맞다! 내 부분에 어리석은 실수.내 C 포인터 구문을 검토 해야하는 것 같습니다. 당신이 말했듯이, 이것은 우연히 약간의 우연이 객체의 기본 구조 표현을 주어진 방식대로 작동했습니다. – nebs

+1

'&'를 사용하면 그 두 끔찍한 캐스트도 제거 할 수 있습니다. – CodaFi

+0

Brilliant! 왜 이것이 효과가 있는지 간단히 설명해 주시겠습니까? itemsPtr은 struct :'id __unsafe_unretained * itemsPtr'에서 이와 같이 정의됩니다. 나의 이해에서'id '는'무언가에 대한 포인터 '를 의미합니다. 그래서 우리가'__unsafe_unretained' 부분을 무시한다면 타입으로'id *'가 있습니다. 이것은'포인터를 가리키는 포인터 '가 맞습니까? 그러면 '&'는 '주소'를 의미합니다. 그래서 & someObject 할 때 그것은 객체의 메모리 주소 인 정수를 돌려줍니다. 나는 왜 & myObject가'id *'에 할당 될 수 있는지 이해할 수 없다. itemsPtr이 myObject의 주소를 보유하고있는 다른 포인터를 가리 킵니까? – nebs

1

귀하의 코드가 디버그 출력이 구현 세부 사항을 공개한다 그것이 방식 괜찮에 (감사

.

NSString is toll-free-bridged with CFString. 즉, NSStringCFString으로 취급하거나 그 반대의 경우도 포인터를 다른 유형으로 캐스팅하면됩니다.

실제로 컴파일 타임 상수 문자열은보고있는 내용 인 __NSCFConstantString 유형의 인스턴스입니다.

소스 코드에 @"hello"을 입력하면 컴파일러는이를 NSString *으로 처리하고 __NSCFConstantString의 인스턴스로 컴파일합니다.

CFSTR("hello")을 소스 코드에 넣으면 컴파일러에서이를 CFStringRef으로 처리하고 __NSCFConstantString의 인스턴스로 컴파일합니다.

런타임에 다른 구문을 사용하여 소스 코드에서 만들었지 만 이러한 개체는 메모리에 차이가 없습니다.

+0

답장을 보내 주셔서 감사합니다. 그 말이 완벽합니다. 그 생각은 대체로 제가 생각한 것입니다. 제 질문에 대한 업데이트를 참조하십시오. 명시 적 캐스트로 이론을 테스트했지만 NSString 메서드를 __NSCFConstantString 객체에 호출 할 수 없습니다. obj-c 객체로 변환하려면 특별한 작업을 수행해야합니까? – nebs

+0

@Nebs 아니요, 캐스팅은 ** 아무 것도하지 않습니다 ** (물론 컴파일러를 속일 수 있습니다). 객체의 클래스 나 응답하는 메시지는 변경되지 않습니다. '__NSCFConstantString'은'NSString'의 적절한 서브 클래스이므로 ** NSString이 응답하는 모든 메시지에 응답해야합니다. 왜 당신이 오류를 얻고있는 것은 ** 클래스 객체 자체에 그것을 보내려고한다는 것입니다 ** 그리고 그것의 인스턴스가 아닙니다. –

+0

네가 맞다. itemsPtr에 잘못된 것을 전달하고 있었기 때문에 내 문제가 캐스팅보다있었습니다. 귀하의 대답은 기술적으로 작성하는 동안, CodaFi의 대답은이 질문의 근원에 도달하므로 그의 대답을 받아 들일 것입니다. 설명 주셔서 감사합니다! – nebs