Không có nghĩa là gì @private mật trong Objective-C?


Câu trả lời:


186

Đó là một công cụ sửa đổi khả năng hiển thị, có nghĩa là các biến thể hiện được khai báo là @privatechỉ có thể được truy cập bởi các thể hiện của cùng một lớp . Các thành viên tư nhân không thể được truy cập bởi các lớp con hoặc các lớp khác.

Ví dụ:

@interface MyClass : NSObject
{
    @private
    int someVar;  // Can only be accessed by instances of MyClass

    @public
    int aPublicVar;  // Can be accessed by any object
}
@end

Ngoài ra, để làm rõ, các phương thức luôn được công khai trong Objective-C. Có nhiều cách để "ẩn" các khai báo phương thức, mặc dù vậy, hãy xem câu hỏi này để biết thêm thông tin.


Điều gì về các biến thể hiện trong dấu ngoặc nhọn sau @im THỰCation? Họ luôn luôn riêng tư?
John Henckel

Tôi biết nó đã cũ ... Nhưng nó không phải là một sửa đổi khả năng hiển thị. Đó là một sửa đổi truy cập. Đó là một sự khác biệt quan trọng hơn trong C ++, nhưng đó cũng là một điểm khác biệt trong Objective-C. Các biến được hiển thị cho trình biên dịch. Trình biên dịch không cho phép bạn truy cập nó.
gnasher729

161

Như htw đã nói, đó là một sửa đổi tầm nhìn. @privatecó nghĩa là ivar (biến thể hiện) chỉ có thể được truy cập trực tiếp từ bên trong một thể hiện của cùng một lớp. Tuy nhiên, điều đó có thể không có ý nghĩa nhiều với bạn, vì vậy hãy để tôi cho bạn một ví dụ. Chúng ta sẽ sử dụng các initphương thức của các lớp làm ví dụ, vì đơn giản. Tôi sẽ bình luận nội tuyến để chỉ ra các mục quan tâm.

@interface MyFirstClass : NSObject
{
    @public
    int publicNumber;

    @protected  // Protected is the default
    char protectedLetter;

    @private
    BOOL privateBool;
}
@end

@implementation MyFirstClass
- (id)init {
    if (self = [super init]) {
        publicNumber = 3;
        protectedLetter = 'Q';
        privateBool = NO;
    }
    return self;
}
@end

@interface MySecondClass : MyFirstClass  // Note the inheritance
{
    @private
    double secondClassCitizen;
}
@end

@implementation MySecondClass
- (id)init {
    if (self = [super init]) {
        // We can access publicNumber because it's public;
        // ANYONE can access it.
        publicNumber = 5;

        // We can access protectedLetter because it's protected
        // and it is declared by a superclass; @protected variables
        // are available to subclasses.
        protectedLetter = 'z';

        // We can't access privateBool because it's private;
        // only methods of the class that declared privateBool
        // can use it
        privateBool = NO;  // COMPILER ERROR HERE

        // We can access secondClassCitizen directly because we 
        // declared it; even though it's private, we can get it.
        secondClassCitizen = 5.2;  
    }
    return self;
}

@interface SomeOtherClass : NSObject
{
    MySecondClass *other;
}
@end

@implementation SomeOtherClass
- (id)init {
    if (self = [super init]) {
        other = [[MySecondClass alloc] init];

        // Neither MyFirstClass nor MySecondClass provided any 
        // accessor methods, so if we're going to access any ivars
        // we'll have to do it directly, like this:
        other->publicNumber = 42;

        // If we try to use direct access on any other ivars,
        // the compiler won't let us
        other->protectedLetter = 'M';     // COMPILER ERROR HERE
        other->privateBool = YES;         // COMPILER ERROR HERE
        other->secondClassCitizen = 1.2;  // COMPILER ERROR HERE
    }
    return self;
}

Vì vậy, để trả lời câu hỏi của bạn, @private bảo vệ ngà khỏi sự truy cập bởi một thể hiện của bất kỳ lớp nào khác. Lưu ý rằng hai phiên bản MyFirstClass có thể truy cập trực tiếp vào tất cả các ngà của nhau; người ta cho rằng vì lập trình viên hoàn toàn kiểm soát trực tiếp lớp này, nên anh ta sẽ sử dụng khả năng này một cách khôn ngoan.


20
Cần phải đề cập rằng việc sử dụng @public, @proteced và @private trong Objective-C là không phổ biến. Cách tiếp cận được ưa thích là luôn luôn sử dụng các phụ kiện.
Georg Schölly

1
@Georg, nhưng làm thế nào để bạn thực thi việc sử dụng các phụ kiện trừ khi bạn đánh dấu ngà của mình với tầm nhìn hạn chế?
Greg Maletic

5
@Georg Schölly: Vì xcode 4.x + tự động đặt @privatevào khuôn mẫu cho một đối tượng, nên nó không còn quá phổ biến nữa.
dawg

1
@Georg Tôi nghĩ rằng @private, @protected có thể được sử dụng cho các trường hợp liên quan đến thừa kế, cá nhân chưa sử dụng nó :)
chunkyguy

5
Cần lưu ý rằng những ngày này, có rất ít lý do để đặt các biến thể hiện trong tiêu đề công khai. Chúng có thể được đặt trực tiếp trên @implementationkhối. Và một khi bạn làm điều đó, chúng thực sự riêng tư bất kể người sửa đổi khả năng hiển thị, vì chúng thậm chí không hiển thị cho bất kỳ ai bên ngoài tệp đó.
BJ Homer

14

Điều quan trọng là phải hiểu ý nghĩa của nó khi ai đó nói rằng bạn không thể truy cập vào một @privatebiến thể hiện. Câu chuyện thực sự là trình biên dịch sẽ báo lỗi cho bạn nếu bạn cố truy cập các biến này trong mã nguồn của mình. Trong các phiên bản trước của GCC và XCode, bạn sẽ chỉ nhận được cảnh báo thay vì lỗi.

Dù bằng cách nào, vào thời gian chạy, tất cả các cược đã tắt. Chúng @private@protectedivars có thể được truy cập bởi một đối tượng của bất kỳ lớp nào. Các công cụ sửa đổi khả năng hiển thị này chỉ gây khó khăn cho việc biên dịch mã nguồn thành mã máy vi phạm mục đích của các công cụ sửa đổi khả năng hiển thị.

Đừng dựa vào công cụ sửa đổi tầm nhìn của ivar để bảo mật! Họ không cung cấp gì cả. Chúng hoàn toàn dành cho việc thực thi thời gian biên dịch các mong muốn của người xây dựng lớp.

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.