2011-04-28 33 views
13

Tôi đã xem qua một loạt bài đăng về chủ đề này. Có lẽ tôi đã không chạy qua "một" và ai đó sẽ chỉ cho tôi theo hướng đó. Câu hỏi rất đơn giản và có thể có một câu trả lời đơn giản.Làm thế nào để khai báo các biến mẫu và các phương thức không hiển thị hoặc không thể sử dụng bên ngoài thể hiện của lớp?

Nếu bạn có hai ivars, nói "public_ivar" và "private_ivar", bạn nên khai báo chúng ở đâu ra công khai và những gì là riêng tư không được hiển thị dưới bất kỳ hình thức nào tập tin?

Câu hỏi tương tự trong trường hợp "public_method" và "private_method".

Tôi thích các tệp tiêu đề sạch (bằng các ngôn ngữ khác) chỉ hiển thị các phương pháp và ivars mà tôi muốn người khác xem. Bạn sẽ có thể xuất bản tập tin tiêu đề của bạn và không chạy vào nguy hiểm của một người nào đó truy cập vào một cái gì đó mà họ không được phép. Làm thế nào để bạn làm điều đó trong mục tiêu-C. Ví dụ, giả sử rằng tôi quyết định rằng tôi cần phải sử dụng một ngà voi để theo dõi một số dữ liệu, một bộ đếm hoặc một cái gì đó tương tự, giữa các phương thức lớp khác nhau mà tất cả đều cần truy cập vào thông tin này. Nếu ivar đó được khai báo thông thường trong header dưới @interface, sự tồn tại của nó được quảng cáo công khai và nó có thể được sử dụng bởi bất cứ ai tạo ra một thể hiện của lớp. Kịch bản lý tưởng sẽ là ngà này sẽ không thể nhìn thấy ở tất cả bên ngoài của việc thực hiện lớp.

Trả lời

17

Bạn có thể khai báo các biến mẫu hoặc thuộc tính được khai báo trong tiện ích mở rộng lớp. Vì tiện ích mở rộng lớp được khai báo trong tệp triển khai (tức là, không phải tệp tiêu đề), chúng sẽ không hiển thị với người nào đó đang kiểm tra tệp tiêu đề. Ví dụ, trong file header:

@interface SomeClass : NSObject 
@end 

và trong các tập tin thực hiện:

@interface SomeClass() 
@property (nonatomic, assign) int privateInt; 
@end 

@implementation SomeClass 

@synthesize privateInt; 
… 
@end 

hoặc

@interface SomeClass() { 
    int privateInt; 
} 
@end 

@implementation SomeClass 
… 
@end 

Lưu ý rằng không có gì ngăn chặn truy cập đến các biến Ví dụ mở rộng tư nhân/lớp là (hoặc các phương thức accessor cho các thuộc tính được khai báo trong một phần mở rộng của lớp) trong suốt thời gian chạy. Tôi đã viết một bài khá chi tiết về vấn đề này như một câu trả lời cho một câu hỏi trên Stack Overflow: Does a private @property create an @private instance variable?

Edit: biến Instance trong phần mở rộng lớp được trình bày trong WWDC phiên 2010 144.

Edit: "Sử dụng trình biên dịch Clang/LLVM 2.0, bạn cũng có thể khai báo các thuộc tính và các biến mẫu trong một phần mở rộng của lớp."

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1

+0

OK, tôi sẽ xem xét điều này. Tôi đang làm một số công việc với thuật toán di truyền và mạng thần kinh. Các lớp học kết thúc với đống các biến cần thiết trong nội bộ. Rất ít trong số này thực sự cần tầm nhìn ở cấp độ tập tin tiêu đề. Ví dụ đầu tiên của bạn về tệp triển khai cho iOS4 + (vì bạn không khai báo int privateInt; trước câu lệnh @property)? –

+0

@Martin Tôi không chắc chắn khi Mục tiêu-C 2.0, cho phép tạo tự động các biến thể hiện sao lưu, đã có sẵn cho iOS. –

+0

@Martin [Trang này trên trang web của Apple] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html%23//apple_ref/doc/uid/ TP40008048-CH106-SW1) không liệt kê một phiên bản iOS cụ thể. –

2

Bạn có thể sử dụng @private để chỉ định các thanh ngang đó là riêng tư. Tuy nhiên, không có cách nào để tạo một phương thức riêng tư. Ngay cả khi phương thức không được liệt kê trong tệp tiêu đề, nếu ai đó biết tên và đối số họ có thể gọi nó.

+0

Vì tôi hiểu nó @private không thực sự làm bất cứ điều gì nếu bạn có khai báo @property (setters và getters). Tôi thậm chí không muốn hàm ivar hoặc thành viên riêng tư nằm trong tiêu đề. Trên giả định rằng không ai biết về họ, họ nên vẫn còn vô hình (chỉ cố gắng để giữ cho người trung thực trung thực, nếu bạn muốn đào bạn có thể khám phá bất cứ điều gì). Tôi chỉ nghĩ rằng nó là "bẩn" để có tất cả các công cụ này trong tiêu đề đó là hoàn toàn không liên quan đến các phần khác của một ứng dụng. –

+1

@Martin: Thuộc tính không phải là một cây ngà. Đối với việc ẩn các dấu gạch ngang trong tiêu đề, tôi có thể nghĩ đến hai tùy chọn: Bạn có thể có chỉ một con trỏ đến một cấu trúc được khai báo ở nơi khác, hoặc bạn có thể có tất cả các cá thể thực sự là các lớp con riêng (dọc theo những gì mà Apple làm với các nhóm lớp). – Anomie

+0

Có tội lười biếng với ngôn ngữ. Tôi hiểu rằng @property chỉ đơn giản là tạo ra các setter cơ bản và mã getter. Nó có làm gì khác không? –

4

Sử dụng class extensions để thêm vào một lớp trong tập tin thực thi của bạn. Một lớp mở rộng về cơ bản là một thể loại chưa được đặt tên với một vài tiền thưởng: các thuộc tính được khai báo trong nó có thể được tổng hợp và bất cứ thứ gì được khai báo trong nó phải nằm trong bản thực thi chính, do đó trình biên dịch có thể kiểm tra để đảm bảo bạn không bỏ lỡ một thực thi. Bạn phải đặt tiện ích mở rộng lớp trước khi triển khai. Bạn không thể thêm trực tiếp các biến mẫu trong một phần mở rộng của lớp, nhưng bạn có thể thêm các thuộc tính.Khi bạn tổng hợp các trình truy cập cho các thuộc tính không có biến mẫu tương ứng, thời gian chạy mới (os x 10.5 trở lên và tất cả các phiên bản iOS, tôi tin) sẽ tạo các biến mẫu tự động. Điều này có nghĩa là bạn không thể tạo các trình truy cập của riêng bạn, tuy nhiên, trừ khi bạn đặt biến thể hiện trong tiêu đề của bạn. Các phương thức riêng có thể được thêm vào phần mở rộng của lớp mà không có giới hạn, nhưng như Anomie đã lưu ý, về mặt kỹ thuật có thể sử dụng chúng nếu bạn biết chúng được gọi là gì, và với lớp-dump, không có gì là an toàn.

Ví dụ sử dụng một phần mở rộng lớp:

@interface MyClass() 
@property (retain) id privateIvar; 
@property (readwrite) id readonlyProperty; // bonus! class extensions can be used to make a property that is publicly readonly and privately readwrite 
- (void)privateMethod; 
@end 
@implementation MyClass 
@synthesize privateIvar; // the runtime will create the actual ivar, and we just access it through the property 
- (void)privateMethod { 
    ... 
} 
... 

Một cách khác để tạo ra "biến dụ" mà không đặt chúng trong tiêu đề hoặc sử dụng một tài sản là sử dụng associative references, mà thêm dữ liệu vào một đối tượng khi chạy. Chúng không giống như các biến mẫu, và cú pháp cho chúng phức tạp hơn. Vì chúng cũng yêu cầu thời gian chạy mới, chỉ có hai lý do bạn thực sự muốn sử dụng chúng: bạn muốn thêm biến thể hiện trong một danh mục (ngoài phạm vi của câu hỏi này) hoặc bạn cần nó là thực sự thực sự riêng tư. Một tham chiếu liên kết không tạo ra bất kỳ phương thức nào hoặc thêm vào định nghĩa của lớp trong mã được biên dịch, vì vậy nếu bạn không tạo trình bao bọc cho chúng thì không thể tìm ra chúng mà không hỏi đối tượng sau khi bạn thêm dữ liệu. Xem phần dưới cùng của trang tôi đã liên kết để biết ví dụ sử dụng hoàn chỉnh.

+0

Vì vậy, ... nếu bạn cần một setter tùy biến hoặc getter cho một ngà "ẩn" theo cách này bạn không thể viết một mà không để lộ ngà trong tiêu đề? –

+0

@Martin: Như Bavarious đã nói, và như đã thảo luận trong các nhận xét, các thanh ngang hiện được hỗ trợ trong các phần mở rộng của lớp, vì vậy bạn có thể khai báo nó ở đó thay vì tiêu đề. Bạn cũng có thể sử dụng các tham chiếu liên kết và viết các trình bao bọc xung quanh chúng như các trình truy cập. – ughoavgfhw

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