Apa yang dimaksud dengan "@private" di Objective-C?

Jawaban:

186

Ini adalah pengubah visibilitas — itu berarti bahwa variabel instance dideklarasikan sebagai @privatehanya dapat diakses oleh instance dari kelas yang sama . Anggota pribadi tidak dapat diakses oleh subclass atau kelas lain.

Sebagai contoh:

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

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

Juga, untuk memperjelas, metode selalu publik di Objective-C. Ada beberapa cara untuk menyembunyikan deklarasi metode, lihat pertanyaan ini untuk informasi lebih lanjut.

hbw
sumber
Bagaimana dengan variabel instan yang ada dalam kurung setelah implementasi @? Apakah mereka selalu pribadi?
John Henckel
Saya tahu ini sudah tua ... Tapi itu bukan pengubah visibilitas. Ini adalah pengubah akses. Ini adalah perbedaan yang lebih penting dalam C ++, tetapi ini adalah perbedaan dalam Objective-C juga. Variabel terlihat oleh kompiler. Kompiler tidak membiarkan Anda mengaksesnya.
gnasher729
161

Seperti yang dikatakan htw, ini adalah pengubah visibilitas. @privateberarti bahwa ivar (variabel instan) hanya dapat diakses langsung dari dalam instance dari kelas yang sama. Namun, itu mungkin tidak berarti banyak bagi Anda, jadi izinkan saya memberi Anda sebuah contoh. Kami akan menggunakan initmetode kelas sebagai contoh, demi kesederhanaan. Saya akan berkomentar sebaris untuk menunjukkan item yang menarik.

@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;
}

Jadi untuk menjawab pertanyaan Anda, @private melindungi gars dari akses oleh instance dari kelas lain. Perhatikan bahwa dua instance MyFirstClass dapat mengakses semua ivars masing-masing secara langsung; diasumsikan bahwa karena programmer memiliki kendali penuh atas kelas ini secara langsung, ia akan menggunakan kemampuan ini dengan bijak.

BJ Homer
sumber
20
Harus disebutkan bahwa tidak biasa menggunakan @public, @proteced dan @private di Objective-C. Pendekatan yang disukai adalah selalu menggunakan accessors.
Georg Schölly
1
@ Georg, tetapi bagaimana Anda menegakkan penggunaan pengakses kecuali Anda menandai ivars Anda dengan visibilitas terbatas?
Greg Maletic
5
@ Georg Schölly: Karena xcode 4.x + secara otomatis menempatkan @privatedalam templat untuk suatu objek, itu tidak biasa lagi.
dawg
1
@ Georg Saya pikir @private, @protected dapat digunakan untuk kasus-kasus di mana warisan terlibat, belum pernah menggunakannya secara pribadi :)
chunkyguy
5
Perlu dicatat bahwa hari ini, ada sangat sedikit alasan untuk meletakkan variabel instan di header publik. Mereka dapat ditempatkan langsung di @implementationblok. Dan begitu Anda melakukannya, mereka secara pribadi aman tidak peduli pengubah visibilitas, karena mereka bahkan tidak terlihat oleh siapa pun di luar file itu.
BJ Homer
14

Penting untuk memahami apa artinya ketika seseorang mengatakan bahwa Anda tidak dapat mengakses @privatevariabel instan. Kisah sebenarnya adalah bahwa kompiler akan memberi Anda kesalahan jika Anda mencoba mengakses variabel-variabel ini dalam kode sumber Anda. Dalam versi GCC dan XCode sebelumnya, Anda hanya akan mendapatkan peringatan alih-alih kesalahan.

Either way, pada saat run time, semua taruhan dibatalkan. Ini @privatedan @protectedivars dapat diakses oleh objek dari kelas apa pun. Pengubah visibilitas ini hanya menyulitkan untuk mengkompilasi kode sumber ke dalam kode mesin yang melanggar maksud pengubah visibilitas.

Jangan mengandalkan pengubah visibilitas ivar untuk keamanan! Mereka tidak memberikan apa pun. Mereka hanya untuk penegakan waktu kompilasi dari keinginan kelas-pembangun.

Jeff Wolski
sumber