Cara mentransmisikan objek di Objective-C


123

Apakah ada cara untuk mentransmisikan objek ke objektif-c seperti cara objek dilemparkan di VB.NET?

Misalnya, saya mencoba melakukan hal berikut:

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

Namun saya mendapatkan kesalahan kompiler karena properti 'list' ada di kelas SelectionListViewController tetapi tidak di FieldEditViewController meskipun SelectionListViewController mewarisi dari FieldEditViewController.

Ini masuk akal, tetapi apakah ada cara untuk mentransmisikan myEditController ke SelectionListViewController sehingga saya bisa mengakses properti 'list'?

Misalnya di VB.NET saya akan melakukan:

CType(myEditController, SelectionListViewController).list = listOfItems

Terima kasih untuk bantuannya!

Jawaban:


216

Ingat, Objective-C adalah superset dari C, jadi typecasting berfungsi seperti halnya di C:

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

21
Atau "Ingat, Objective-C berfungsi seperti Java, ingatlah untuk menambahkan tanda bintang ke variabel yang mengarah ke objek Obj-C."
Dan Rosenstark

1
Jawaban yang bagus. Anda bisa membuatnya sedikit lebih jelas dengan membagi pemeran dan tugas menjadi dua baris.
Guido Anselmi

1
Typecasting di Objective-C jauh lebih mirip C lama daripada Java. Java menyembunyikan sebagian besar ini dari pengguna, oleh karena itu argumen bahwa C masih harus diajarkan daripada Java sebagai bahasa pertama.
csmith

11
((SelectionListViewController *)myEditController).list

Contoh lainnya:

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

7
Secara umum ini benar; Anda tidak perlu memasukkan id dalam ekspresi pesan. Namun saat menggunakan sintaks titik untuk mengakses dan menyetel properti, Anda harus menggunakan tipe konkret, bukan hanya id, sehingga compiler mengetahui pemanggilan metode apa yang sebenarnya akan dihasilkan. (Ini dapat berbeda untuk properti dengan nama yang sama.)
Chris Hanson

9

Typecasting di Objective-C semudah:

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

Namun, apa yang terjadi jika objek pertama tidak UIViewdan Anda mencoba menggunakannya:

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

Ini akan crash. Dan mudah untuk menemukan crash seperti itu untuk kasus ini, tetapi bagaimana jika baris tersebut berada di kelas yang berbeda dan baris ketiga dijalankan hanya sekali dalam 100 kasus. Saya yakin pelanggan Anda menemukan kecelakaan ini, bukan Anda! Solusi yang masuk akal adalah crash lebih awal , seperti ini:

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

Penegasan tersebut tidak terlihat bagus, jadi kami dapat memperbaikinya dengan kategori praktis ini:

@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

Ini jauh lebih baik:

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

PS Untuk jenis keamanan koleksi Xcode 7 memiliki jauh lebih baik daripada typecasting - generik


4

Tentu, sintaksnya persis sama dengan C - NewObj* pNew = (NewObj*)oldObj;

Dalam situasi ini Anda mungkin ingin mempertimbangkan untuk menyediakan daftar ini sebagai parameter ke konstruktor, seperti:

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

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

  return self;
}

Kemudian gunakan seperti ini:

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

0

Casting untuk dimasukkan sama pentingnya dengan casting untuk pengecualian untuk programmer C ++. Jenis pengecoran tidak sama dengan RTTI dalam arti bahwa Anda dapat mentransmisikan objek ke jenis apa pun dan penunjuk yang dihasilkan tidak akan nihil.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.