Objective-C에서 개체를 캐스팅하는 방법


123

객체가 VB.NET에서 캐스팅되는 방식과 같이 Objective-C에서 객체를 캐스팅하는 방법이 있습니까?

예를 들어, 다음을 시도하고 있습니다.

// create the view controller for the selected item
FieldEditViewController *myEditController;
switch (selectedItemTypeID) {
    case 3:
        myEditController = [[SelectionListViewController alloc] init];
        myEditController.list = listOfItems;
        break;
    case 4:
        // set myEditController to a diff view controller
        break;
}

// load the view
[self.navigationController pushViewController:myEditController animated:YES];
[myEditController release]; 

그러나 'list'속성이 SelectionListViewController 클래스에 존재하지만 SelectionListViewController가 FieldEditViewController에서 상속하더라도 FieldEditViewController에는 없기 때문에 컴파일러 오류가 발생합니다.

이것은 의미가 있지만 'list'속성에 액세스 할 수 있도록 myEditController를 SelectionListViewController로 캐스팅하는 방법이 있습니까?

예를 들어 VB.NET에서는 다음을 수행합니다.

CType(myEditController, SelectionListViewController).list = listOfItems

도와 주셔서 감사합니다!

답변:


216

Objective-C는 C의 상위 집합이므로 형변환은 C에서와 같이 작동합니다.

myEditController = [[SelectionListViewController alloc] init];
((SelectionListViewController *)myEditController).list = listOfItems;

21
또는 "Objective-C는 Java처럼 작동합니다. Obj-C 객체를 가리키는 변수에 별표를 추가하는 것을 잊지 마십시오."
Dan Rosenstark

1
좋은 대답입니다. 캐스트와 할당을 두 줄로 나누면 좀 더 명확하게 만들 수 있습니다.
Guido Anselmi

1
Objective-C의 Typecasting은 Java보다 이전 C와 훨씬 비슷합니다. 자바는이 대부분을 사용자에게 숨기므로 자바가 아닌 제 1 언어로 C를 가르쳐야한다고 주장합니다.
csmith

11
((SelectionListViewController *)myEditController).list

더 많은 예 :

int i = (int)19.5f; // (precision is lost)
id someObject = [NSMutableArray new]; // you don't need to cast id explicitly

7
일반적으로 이것은 정확합니다. 메시지 표현식에서 ID를 캐스팅 할 필요가 없습니다. 그러나 도트 구문을 사용하여 속성에 액세스하고 설정하는 경우 id뿐만 아니라 구체적인 유형을 사용해야하므로 컴파일러는 실제로 생성 할 메서드 호출을 알고 있습니다. (이 같은 이름을 가진 속성에 대한 다를 수 있습니다.)
크리스 핸슨에게

9

Objective-C의 타입 캐스팅은 다음과 같이 쉽습니다.

NSArray *threeViews = @[[UIView new], [UIView new], [UIView new]];
UIView *firstView = (UIView *)threeViews[0];

그러나 첫 번째 개체가 그렇지 않고 UIView사용하려고 하면 어떻게 되나요 ?

NSArray *threeViews = @[[NSNumber new], [UIView new], [UIView new]];
UIView *firstView = (UIView *)threeViews[0];
CGRect firstViewFrame = firstView.frame; // CRASH!

충돌합니다. 그리고이 경우 이러한 크래시를 쉽게 찾을 수 있지만, 그 라인이 다른 클래스에 있고 세 번째 라인이 100 개의 경우에 한 번만 실행된다면 어떻게 될까요? 나는 당신이 아니라 당신의 고객이이 충돌을 발견 할 것이라고 장담한다! 그럴듯한 해결책은 다음과 같이 일찍 충돌하는 것입니다.

UIView *firstView = (UIView *)threeViews[0];
NSAssert([firstView isKindOfClass:[UIView class]], @"firstView is not UIView");

이러한 주장은별로 좋지 않으므로 다음과 같은 편리한 범주로 개선 할 수 있습니다.

@interface NSObject (TypecastWithAssertion)
+ (instancetype)typecastWithAssertion:(id)object;
@end


@implementation NSObject (TypecastWithAssertion)

+ (instancetype)typecastWithAssertion:(id)object {
    if (object != nil)
        NSAssert([object isKindOfClass:[self class]], @"Object %@ is not kind of class %@", object, NSStringFromClass([self class]));
    return object;
}

@end

이것은 훨씬 낫습니다.

UIView *firstView = [UIView typecastWithAssertion:[threeViews[0]];

- 컬렉션 유형 안전 엑스 코드 7의 PS는 훨씬 더 타입 캐스팅 이상이 제네릭을


4

물론 구문은 C와 똑같습니다. NewObj* pNew = (NewObj*)oldObj;

이 상황에서 다음과 같이이 목록을 생성자에 대한 매개 변수로 제공하는 것을 고려할 수 있습니다.

// SelectionListViewController
-(id) initWith:(SomeListClass*)anItemList
{
  self = [super init];

  if ( self ) {
    [self setList: anItemList];
  }

  return self;
}

그런 다음 다음과 같이 사용하십시오.

myEditController = [[SelectionListViewController alloc] initWith: listOfItems];

0

포함을위한 캐스팅은 C ++ 프로그래머의 제외를위한 캐스팅만큼 중요합니다. 유형 캐스팅은 객체를 모든 유형으로 캐스팅 할 수 있고 결과 포인터가 nil이 아니라는 점에서 RTTI와 동일하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.