2009-07-30 36 views
7

Tôi có một chức năng mà tôi muốn hoạt động trên hai đối tượng tùy chỉnh khác nhau. Suy nghĩ đầu tiên của tôi là chấp nhận đối số dưới dạng (id) và hoạt động trên đối tượng id. Tôi có thể không hoàn toàn có vẻ để tìm ra cách để làm điều đó, tuy nhiên.Sử dụng (id) trong Mục tiêu-C

Cả lớp (nói táo và cam) có các biến giao diện:

NSDecimalNumber *count; 

tôi muốn làm một cái gì đó tương tự như sau:

-(NSDecimalNumber*)addCount:(id)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 
} 

tôi dường như không thể tìm ra các cú pháp để làm điều đó xảy ra. Đây có phải là cách tiếp cận thích hợp, hoặc nó sẽ tốt hơn để phân lớp (từ nói một lớp trái cây) và hoạt động trên lớp cha mẹ?

-(NSDecimalNumber*)addCount:(Fruit*)addFruit{ 

    return [count decimalNumberByAdding:addFruit.count]; 
} 

Trả lời

12

Trong khi bạn có thể gửi thư đến bất kỳ đối tượng nào (id) - trình truy cập thuộc tính yêu cầu trình biên dịch biết loại bạn đang xử lý - điều này là do trình truy cập thuộc tính là cú pháp đường xung quanh gọi phương thức getter và setter cụ thể.

Bạn có một vài cách để làm việc xung quanh này:

  1. Thay vì truy cập vào thuộc tính đếm, gọi các phương pháp tương ứng [getCount].

  2. Nếu các lớp khác nhau có những phiên bản khác nhau của phương pháp này, bạn có thể sử dụng một tấm séc loại runtime:

  3. Cung cấp một lớp cơ sở cho cả hai loại để bạn có thể vượt qua trong một cái gì đó cụ thể hơn (id).

  4. Xác định và triển khai Giao thức mà cả hai đối tượng thực hiện xác định thuộc tính đếm (hoặc phương pháp).

Ví dụ về một tấm séc loại động:

if([object isKindOfClass:[Apple Class]) 
    // call one overload of getCount 
else if([object isKindOfClass:[Orange Class]) 
    // call another overload of getCount 

Cá nhân, tôi ủng hộ gõ mạnh trong mã của tôi bởi vì nó làm cho nó dễ dàng hơn để hiểu được ý định. Nó cũng cho phép IDE hỗ trợ nỗ lực mã hóa của bạn với các tính năng phân tích tĩnh, phân tích tĩnh và tái cấu trúc. Vì vậy, trong trường hợp của bạn, tôi sẽ sử dụng hoặC# 3 hoặC# 4 như là một cách tiếp cận - tùy thuộc vào việc thừa kế là thực sự thích hợp cho vấn đề.

+1

Tôi là một fan hâm mộ mạnh mẽ đánh máy bản thân mình (tôi đã đi với # 4 FYI). Cảm ơn rất nhiều cho các thông tin; điều này thật đúng với gì mà tôi đã tìm kiếm! –

+0

Nếu bạn thực sự cần gõ mạnh, bạn có thể có thời gian tốt hơn với ngôn ngữ tĩnh như C++. Đó là một sự xấu hổ mà tài sản cư xử theo cách này không đối xứng. Ít nhất thì phải có cờ trình biên dịch để cho phép hành vi biên dịch đối xứng giữa cú pháp thuộc tính và cú pháp phương thức nhận. – ctpenrose

+0

@ctpenrose Obj-C có thể được đánh máy tĩnh như ngôn ngữ kế tiếp nếu bạn muốn. – kubi

0

Bạn đang gửi tin nhắn để đếm, số lượng là bao nhiêu? id là một con trỏ đến bất kỳ loại đối tượng nào. Nếu bạn mong đợi đối tượng có thuộc tính count, thì bạn chỉ có thể truyền vào một Array (hoặc một số hạn chế kiểu khác).

-(NSDecimalNumber*)addCount:(NSArray*) Object{ 

return [count decimalNumberByAdding: [Object count]]; 

} 
0

Theo tôi được biết, id không có bất kỳ phương pháp hoặc các biến liên kết với nó vì nó là một con trỏ chung mà không đề cập đến bất kỳ lớp học cụ thể. This page có một số thông tin tốt về id nếu bạn cuộn xuống một chút.

anObject điều này sẽ không có biến số count, đó là lý do tại sao lần thử đầu tiên của bạn không hoạt động. Tạo một lớp cơ sở và sử dụng nó như một tham số cho phương thức có vẻ như là ý tưởng tốt nhất cho tôi.

8

Bạn nên cố gắng không truy cập các biến mẫu từ một lớp khác.

Trong mục tiêu-C, đủ để hai đối tượng phản hồi cùng một bộ chọn (giả sử count), tuy nhiên điều đó sẽ cho bạn một cảnh báo trình biên dịch.

Có hai cách bạn có thể loại bỏ cảnh báo này: hoặc bằng cách phân lớp từ lớp phổ biến Fruit hoặc bằng cách có hai lớp của bạn phù hợp với một giao thức. Tôi muốn đi với giao thức:

@protocol FruitProtocol 

- (NSDecimalNumber *)count; 

@end 

@interface Orange : NSObject<FruitProtocol> 
@end 

@interface Apple : NSObject<FruitProtocol> 
@end 

Sau đó, phương pháp của bạn có thể trông như thế này:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addFruit { 
    return [count decimalNumberByAdding:[addFruit count]]; 
} 

Ở đây bạn đang nói rằng bạn addCount hy vọng bất kỳ đối tượng đó phù hợp với các giao thức FruitProtocol, và do đó có thể phản hồi bộ chọn count, do đó trình biên dịch sẽ chấp nhận nó.

+0

wrt/"Bạn không thể truy cập các biến mẫu từ một lớp khác." Bạn chắc chắn nhất có thể. Nếu bạn gõ tĩnh một đối tượng, tức là đối tượng 'MYObject *;', thì bạn có thể truy cập các biến cá thể của nó từ bất kỳ lớp nào bằng toán tử '->'. Ví dụ, giả sử 'MYObject' có một' int' ivar có tên 'count', bạn có thể sử dụng' int myCount = object-> count; 'để truy cập nó. Các biện pháp bảo vệ được cung cấp bởi '@ private', vv, chỉ là mỹ phẩm, ngay cả trong ObjC2. – johne

+0

Điều này thật tuyệt! Mẫu mã của bạn giúp tôi dễ dàng triển khai mà không cần đào sâu thêm nữa. Cám ơn rất nhiều! –

+0

Bạn đúng johne, tôi sẽ thay đổi nó thành "bạn không nên". Cảm ơn bạn – pgb

1

Thực tế là bạn đang cố truy cập 'addFruit.count' là vấn đề. Cú pháp chấm chỉ dành cho các thuộc tính được khai báo với @property (hoặc cho các cấu trúc). Nếu bạn thay đổi nó để

[addFruit count] 

và thêm

-(NSDecimalNumber*)count 
{ 
    return [[count retain] autorelease]; 
} 

cho từng lớp, sau đó nó sẽ làm việc. Tuy nhiên, bạn sẽ nhận thấy bạn sẽ nhận được cảnh báo rằng 'id' có thể không phản hồi thông điệp 'đếm' và trừ khi bạn có thể chắc chắn rằng các mục được gửi tới phương pháp này thực hiện phương pháp 'đếm', đây là một cách tiếp cận có vấn đề .

Tôi đồng ý với cách tiếp cận của pgb. Bạn nên định nghĩa một giao thức và khai báo cả hai lớp để thực hiện giao thức đó. Điều này giúp loại bỏ vấn đề không biết liệu đối tượng có phản ứng với 'đếm' hay không, vì bây giờ bạn có 'hợp đồng' các loại.

Nếu bạn muốn giữ lại các dấu chấm cú pháp với một tài sản, bạn có thể khai báo nó trong giao thức:

@protocol FruitProtocol 

@property(readonly) NSDecimalNumber * count; 

- (NSDecimalNumber *)count 

@end 

và sau đó, chức năng của bạn sẽ là:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 

} 
+0

Cũng tuyệt vời! Tôi đã không bắt được điều này trước đó. Cảm ơn vì tiền hỗ trợ! –

Các vấn đề liên quan