2011-10-26 43 views
36

Tôi biết rằng khi chúng ta muốn tạo một đối tượng giá trị không xác định, chúng tôi sử dụng id. Tuy nhiên, tôi tò mò rằng tại sao Apple chọn id quyết định giá trị của nó trong thời gian chạy, khi mọi đối tượng là một lớp con của NSObject. Vì vậy, thay vì id delegate chúng tôi có thể đã sử dụng NSObject *delegate Có ai biết tại sao không? Cảm ơn.Tại sao nên sử dụng id khi chúng ta có thể sử dụng NSObject?

+1

NSProxy là một lớp gốc khác cung cấp cacao. –

+0

NSObject chứa con trỏ isa, id không. Hãy xem http://stackoverflow.com/a/19634973/944634 –

+0

những gì lol? id là một con trỏ isa. http://stackoverflow.com/questions/1990695/in-cocoa-how-is-the-id-type-defined – TheAmateurProgrammer

Trả lời

39

id xóa loại và tương đương với việc nói "đối tượng này phản hồi với bất kỳ bộ chọn nào hiển thị với bản dịch". tất nhiên, đó là trách nhiệm của bạn để đảm bảo chương trình của bạn là chính xác khi bạn xóa các loại (và cũng có thể khi bạn nhập chúng).

Nếu loại là NSObject, trình biên dịch sẽ nói "NSObject có thể không phản hồi bộ chọn" nếu bộ chọn không được khai báo trong giao diện của NSObject hoặc giao thức mà nó chấp nhận. Trong sự kiện đó, bạn cũng có thể thêm một typecast để đúc nó vào loại bạn mong đợi.

Với các loại nghiêm ngặt/chính xác, trình biên dịch có thể khởi động và giúp bạn, điều này rất tuyệt vì ObjC là một ngôn ngữ rất năng động.

id đặc biệt hữu ích khi sử dụng (hoặc xây dựng) các loại bộ sưu tập. Thêm một đối tượng sẽ không là vấn đề trừ khi bạn đã định nghĩa một kiểu gốc mới (không thừa kế từ NSObject). Lấy một giá trị từ bộ sưu tập sẽ yêu cầu một typecast nếu chúng ta sử dụng nó như một cái gì đó khác với lớp cơ sở của chúng ta (NSObject).

Mục tiêu-C không hỗ trợ Generics - bạn không thể, ví dụ: khai báo số NSArray trong số NSString s. Bạn có thể điền một số NSArray với NSString s và chuyển số này qua id để có phong cách viết tự nhiên hơn khi loại an toàn không được giữ nguyên (một la generics).

Vì vậy, hãy mở rộng điều này bằng một số mã thực.

Ví dụ A

NSString * string = [array objectAtIndex:0]; // << trust me (via id) 
return [string length]; 
-or- 
return [[array objectAtIndex:0] length]; // << trust me (via id) 

Ví dụ B

Và bây giờ chúng ta hãy nói id không có sẵn và chúng tôi sửa chữa tất cả các cảnh báo trình biên dịch của chúng tôi bởi vì đó là điều đúng đắn nên làm:

NSString * string = (NSString*)[array objectAtIndex:0]; // << typecast == trust me 
return [string length]; 
-or- 
return [(NSString*)[array objectAtIndex:0] length]; // << typecast == trust me 

id không quyết định giá trị của nó trong thời gian chạy, cũng không phải doe bất kỳ NSObject. Đối tượng ObjC không thực hiện các quảng cáo ngầm, chúng chỉ truyền con trỏ mà không cần quảng cáo chính thức.

liên quan đến ví dụ của bạn, tôi thực sự tuyên bố đại biểu và các thông số của tôi như NSObjects với các giao thức:

NSObject<MONShapeDelegate>* delegate; 
+0

Nó có thể khác với các trình biên dịch khác so với các trình biên dịch tôi đã sử dụng, nhưng theo như tôi biết, nếu bạn khai báo một kiểu như NSObject , trình biên dịch sẽ cho rằng đối tượng thực hiện tất cả các phương thức của SomeProtocol, thậm chí cả các phương thức tùy chọn. – Aberrant

+0

@Aberrant nếu phương thức đại biểu là tùy chọn, tùy thuộc vào * người gọi * để xác minh đối tượng phản hồi với bộ chọn. – justin

+0

Tôi biết, đó là lý do tại sao tôi nói trình biên dịch giả định chúng được triển khai. Nếu không, các tùy chọn sẽ luôn gây cảnh báo, vì trình biên dịch không thể chắc chắn nếu các đối tượng sẽ phản hồi khi chạy. – Aberrant

2

mọi đối tượng là một lớp con của NSObject

Đó không phải là chính xác. Bạn có thể làm cho một đối tượng kéo dài từ không có gì là một lớp gốc.

Đó có lẽ là lý do id được giới thiệu.

11

mọi đối tượng là một lớp con của NSObject

Đó là một tuyên bố không chính xác. Bạn có thể tạo các đối tượng không kế thừa từ NSObject. nó không thực sự được đề nghị, nhưng nó là có thể.

NSProxy là một ví dụ - nó không được kế thừa từ NSObject.

+3

Đây chỉ là bản sao câu trả lời của tôi! –

+1

Xin lỗi:/Tôi đã viết nó khi không có câu trả lời, bạn đánh tôi đến cú đấm ... không có cảm giác khó khăn và không thực sự cần thiết cho một cuộc bỏ phiếu xuống ... Ngoài ra, bạn đã không đề cập đến 'NSProxy' ... – Jasarien

+1

Nếu đó là ngăn xếp và câu trả lời này ở dưới cùng thì @Jasarien đã trả lời trước hết;) – beryllium

3
typedef struct objc_object { 
    Class isa; 
} *id; 

Trên đây là định nghĩa thực tế của id trong ngôn ngữ mục tiêu-C. Hệ thống thời gian chạy Objective-C được xây dựng xung quanh idClass. Không có gì phải làm với NSObject hoặc lớp siêu phổ biến.

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW3

Các NSObject Lớp

NSObject là một lớp rễ, và do đó không có một lớp cha. Nó định nghĩa khung cơ bản cho các đối tượng Objective-C và các tương tác đối tượng. Nó truyền đạt các lớp và các thể hiện của các lớp kế thừa từ nó khả năng hoạt động như các đối tượng và hợp tác với hệ thống thời gian chạy .

Lớp học không cần kế thừa bất kỳ hành vi đặc biệt nào từ lớp khác vẫn nên được tạo thành lớp con của lớp NSObject. Các trường hợp của lớp phải ít nhất có khả năng hoạt động như các đối tượng mục tiêu Mục tiêu-C khi chạy. Thừa kế khả năng này từ lớp NSObject đơn giản hơn nhiều và đáng tin cậy hơn nhiều so với việc phát minh lại nó trong định nghĩa lớp mới.

Tôi nghĩ, điều này là do ban đầu nó là C không phải C++ (hoặc các ngôn ngữ nhập văn bản nghiêm ngặt hơn).

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