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]; 

しかし、SelectionListViewControllerがFieldEditViewControllerを継承していても、SelectionListViewControllerクラスには 'list'プロパティが存在し、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、2014年

1
すばらしい答えです。キャストと割り当てを2行に分割することで、少しわかりやすくすることができます。
グイドアンセルミ

1
Objective-Cでの型キャストは、Javaよりもはるかに古いCに似ています。Javaはこれの大部分をユーザーから隠しているため、JavaではなくCを第一言語として教える必要があるという主張があります。
csmith 2016年

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ではなく具象型を使用する必要があります。これにより、コンパイラーは実際に生成するメソッド呼び出しを認識します。(同じ名前のプロパティでも異なる場合があります。)
Chris Hanson、

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!

クラッシュします。この場合、このようなクラッシュを見つけるのは簡単ですが、これらの行が異なるクラスにあり、3行目が100ケースに1回だけ実行された場合はどうでしょうか。私はあなたの顧客がこのクラッシュを見つけたに違いない!もっともらしい解決策は、このように早くクラッシュすることです:

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]];

PSコレクションのタイプセーフティXcode 7はタイプキャストよりもはるかに優れています- ジェネリック


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.