Cách truyền một đối tượng trong Objective-C


123

Có cách nào để ép các đối tượng trong mục tiêu-c giống như cách các đối tượng được đúc trong VB.NET không?

Ví dụ: tôi đang cố gắng làm như sau:

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

Tuy nhiên, tôi đang gặp lỗi trình biên dịch vì thuộc tính 'list' tồn tại trong lớp SelectionListViewController nhưng không có trên FieldEditViewController mặc dù SelectionListViewController kế thừa từ FieldEditViewController.

Điều này có lý, nhưng có cách nào để truyền myEditController thành SelectionListViewController để tôi có thể truy cập thuộc tính 'list' không?

Ví dụ trong VB.NET, tôi sẽ làm:

CType(myEditController, SelectionListViewController).list = listOfItems

Cảm ơn đã giúp đỡ!

Câu trả lời:


216

Hãy nhớ rằng, Objective-C là một tập hợp con của C, vì vậy việc đánh máy hoạt động giống như trong C:

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

21
Hoặc "Hãy nhớ, Objective-C hoạt động giống như Java, chỉ cần nhớ thêm dấu hoa thị vào các biến trỏ đến đối tượng obj-C."
Dan Rosenstark

1
Câu trả lời chính xác. Bạn có thể làm cho nó rõ ràng hơn một chút bằng cách chia dàn diễn viên và phân công thành hai dòng.
Guido Anselmi

1
Đánh máy trong Objective-C giống với C cũ hơn là Java. Java che giấu hầu hết điều này với người dùng, do đó các lập luận rằng C vẫn nên được dạy chứ không phải là Java như một ngôn ngữ đầu tiên.
csmith

11
((SelectionListViewController *)myEditController).list

Các ví dụ khác:

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

7
Nói chung điều này là chính xác; bạn không cần truyền id trong biểu thức tin nhắn. Nhưng khi sử dụng cú pháp dấu chấm để truy cập và đặt thuộc tính, bạn phải sử dụng một kiểu cụ thể, không chỉ id, vì vậy trình biên dịch biết phương thức nào thực sự cần tạo ra. (Nó có thể khác nhau đối với tài sản có cùng tên.)
Chris Hanson

9

Đánh máy trong Objective-C dễ dàng như sau:

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

Tuy nhiên, điều gì sẽ xảy ra nếu đối tượng đầu tiên không phải là UIViewvà bạn cố gắng sử dụng nó:

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

Nó sẽ sụp đổ. Và thật dễ dàng để tìm thấy lỗi như vậy cho trường hợp này, nhưng điều gì sẽ xảy ra nếu các dòng đó ở các lớp khác nhau và dòng thứ ba chỉ được thực thi một lần trong 100 trường hợp. Tôi cá là khách hàng của bạn tìm thấy sự cố này, không phải bạn! Một giải pháp hợp lý là sụp đổ sớm , như sau:

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

Những xác nhận đó trông không đẹp cho lắm, vì vậy chúng tôi có thể cải thiện chúng với danh mục hữu ích này:

@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

Điều này tốt hơn nhiều :

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

PS Đối với bộ sưu tập, kiểu an toàn Xcode 7 tốt hơn nhiều so với kiểu đánh máy - generics


4

Chắc chắn, cú pháp hoàn toàn giống với C - NewObj* pNew = (NewObj*)oldObj;

Trong trường hợp này, bạn có thể muốn xem xét việc cung cấp danh sách này như một tham số cho hàm tạo, giống như:

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

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

  return self;
}

Sau đó sử dụng nó như thế này:

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

0

Truyền để đưa vào cũng quan trọng như truyền để loại trừ đối với một lập trình viên C ++. Kiểu ép kiểu không giống với RTTI theo nghĩa là bạn có thể ép kiểu đối tượng thành bất kỳ kiểu nào và con trỏ kết quả sẽ không bằng 0.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.