Bagaimana garis bawah di depan variabel dalam kelas objektif-c kakao bekerja?

157

Saya telah melihat dalam beberapa contoh iPhone bahwa atribut telah menggunakan garis bawah _ di depan variabel. Adakah yang tahu apa artinya ini? Atau bagaimana cara kerjanya?

File antarmuka yang saya gunakan terlihat seperti:

@interface MissionCell : UITableViewCell {
    Mission *_mission;
    UILabel *_missionName;
}

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

Saya tidak yakin persis apa yang dilakukan di atas tetapi ketika saya mencoba menetapkan nama misi seperti:

aMission.missionName = missionName;

Saya mendapatkan kesalahan:

meminta anggota 'missionName' dalam sesuatu yang bukan struktur atau kesatuan

Atma
sumber

Jawaban:

97

Jika Anda menggunakan awalan garis bawah untuk guci Anda (yang tidak lebih dari sebuah konvensi umum, tetapi yang bermanfaat), maka Anda perlu melakukan 1 hal tambahan sehingga pengakses yang dibuat secara otomatis (untuk properti) tahu mana yang digunakan untuk menggunakan ivar. Secara khusus, dalam file implementasi Anda, Anda synthesizeakan terlihat seperti ini:

@synthesize missionName = _missionName;

Secara lebih umum, ini adalah:

@synthesize propertyName = _ivarName;
Kelan
sumber
78
dengan properti sintesis otomatis ini tidak lagi diperlukan. Xcode mensintesis @property xxxx dengan ivar bernama _xxxx di belakang layar. Rapi.
LearnCocos2D
@ LearnCocos2D Hai! Seorang pemula untuk iOS di sini dan ada sesuatu yang perlu saya klarifikasi. Selama ini apa yang saya lakukan adalah mendeklarasikan propertydalam file .h dan pada file .m saya mengaksesnya menggunakan selfseperti itu self.someProperty,. Apakah ini cara yang benar? Atau haruskah saya menggunakan ivars dalam kode?
Isuru
mengatur ivar tidak menjalankan properti setter - Anda memutuskan apakah itu ide yang bagus atau tidak untuk setiap kasus tertentu
LearnCocos2D
Pertanyaan Noob: mengapa tidak menggunakan ivars secara langsung? mengapa saya harus mendeklarasikan var terpisah untuk memegang ivar?
Allen
1
@ Allen, jika saya memahami pertanyaan Anda dengan benar: Var terpisah yang Anda deklarasikan adalah pointer ke variabel aktual. Ini penting karena beberapa alasan (yang saya tahu) Pertama, ketika Anda melewatkan sebuah pointer ke fungsi Anda tidak menduplikasi nilainya. Anda hanya memberi tahu fungsi tempat menemukan nilai untuk digunakan. Ini membantu menjaga memori Anda tetap rendah (dan juga membantu dengan mengalokasikan dan membatalkan alokasi memori, yang penting karena tidak adanya 'pengumpulan sampah' yang akan Anda temukan di Jawa)
David Sigley
18

Ini hanya sebuah konvensi untuk keterbacaan, tidak melakukan sesuatu yang khusus untuk kompiler. Anda akan melihat orang menggunakannya pada variabel instance pribadi dan nama metode. Apple sebenarnya merekomendasikan untuk tidak menggunakan garis bawah (jika Anda tidak berhati-hati Anda bisa menimpa sesuatu di superclass Anda), tetapi Anda tidak boleh merasa tidak enak mengabaikan saran itu. :)

Marc Charbonneau
sumber
19
Dari apa yang saya pahami, Apple merekomendasikan untuk tidak menggunakan awalan garis bawah pada nama metode (mereka mencadangkannya sendiri sebagai konvensi untuk metode pribadi), tetapi mereka tidak memiliki rekomendasi semacam itu tentang contoh nama variabel.
Kelan
9
@Kelan Faktanya, Apple menganjurkan untuk melakukannya : "Biasanya, Anda tidak boleh mengakses variabel instan secara langsung, sebaliknya Anda harus menggunakan metode accessor (Anda melakukan variabel akses langsung pada metode init dan dealloc). Untuk membantu memberi sinyal ini, awalan instance misalnya nama variabel dengan garis bawah (_), misalnya: \ @implementation MyClass {BOOL _showsTitle;} "
dmirkitanov
Saya sebenarnya tidak berpikir Apple mendorong kita untuk melakukannya, karena semua kode sampel mereka sendiri di Perpustakaan Pengembang iOS tidak memiliki ( ) di dalamnya. Apple juga mengatakan bahwa mereka telah memesannya, yang harus berarti bahwa mereka menggunakannya secara internal untuk kerangka kerja mereka sendiri seperti UIKit dll. Itulah sebabnya kita tidak boleh sembarangan menggunakannya. Tapi saya melihat bahwa, di tautan Anda memberikan @kelan. Mereka benar-benar mengatakan dalam "riwayat revisi" bahwa "cocok" untuk digunakan ( ). Yang saya artikan adalah kita "bisa" menggunakannya jika kita mau.
WYS
Dokumentasi Apple yang mengatakan tidak menggunakan awalan garis bawah untuk nama metode ada di sini .
ThomasW
9

Satu-satunya tujuan berguna yang telah saya lihat adalah untuk membedakan antara variabel lokal dan variabel anggota seperti yang disebutkan di atas, tetapi itu bukan konvensi yang diperlukan. Ketika dipasangkan dengan @property, itu meningkatkan verbositas dari pernyataan synthesize - @synthesize missionName = _missionName;, dan jelek di mana-mana.

Alih-alih menggunakan garis bawah, cukup gunakan nama variabel deskriptif dalam metode yang tidak bertentangan. Ketika mereka harus konflik, nama variabel dalam metode harus menderita garis bawah, bukan variabel anggota yang dapat digunakan oleh beberapa metode . Satu-satunya tempat umum ini berguna adalah dalam setter atau metode init. Selain itu, ini akan membuat pernyataan @synthesize lebih ringkas.

-(void)setMyString:(NSString*)_myString
{
    myString = _myString;
}

Sunting: Dengan fitur kompiler terbaru sintesis otomatis, saya sekarang menggunakan garis bawah untuk ivar (pada kesempatan yang jarang saya perlu menggunakan ivar untuk mencocokkan apa yang sintesis otomatis lakukan.

Peter DeWeese
sumber
Sebaliknya. variabel pribadi digarisbawahi. properti tidak. dan ketika mereka mensintesisnya, Anda berpasangan dengan mereka.
Justin
Persis seperti yang saya jelaskan, kecuali bahwa saya menyebutnya "variabel anggota" dan bukan "variabel pribadi".
Peter DeWeese
Aduh! Ini meminta masalah ... sintesis otomatis akan membuat ivar _myString yang berarti setter Anda tidak akan berfungsi (karena itu tidak akan dapat memberitahu ivar Anda dari parameter metode).
geowar
Benar, itulah sebabnya saya menambahkan hasil edit di bagian akhir ketika apel menambahkan sintesis otomatis.
Peter DeWeese
5

Itu tidak benar-benar berarti apa-apa, itu hanya konvensi yang digunakan beberapa orang untuk membedakan variabel anggota dari variabel lokal.

Sedangkan untuk kesalahan, sepertinya aMission memiliki tipe yang salah. Apa itu deklarasi?

smorgan
sumber
Ini umum dalam IDE dengan intellisense; itu akan membuat variabel anggota / modul / kelas Anda ditampilkan di bagian atas daftar. Previx umum lainnya adalah "m_"
STW
1
jika itu tidak berarti apa-apa bagaimana Anda bisa beralih antara _missionName dan missionName seperti dalam contoh saya di atas? Deklarasi saya terlihat seperti: Mission * aMission = [[Alokasi misi] init]; aMission.missionName = @ "a mission";
Atma
1
Satu adalah variabel instan dan yang lainnya adalah properti. Anda tidak dapat mengakses variabel instan dengan sintaks seperti aMission.missionName, karena sintaks itu tidak berfungsi dengan pointer.
Chuck
Juga, perhatikan bahwa Anda mencoba untuk beroperasi pada objek Mission, tetapi antarmuka yang telah Anda posting dengan properti missionName adalah MissionCell.
smorgan
2

Ini hanya untuk konvensi penamaan properti sintesis.

Ketika Anda mensintesis variabel dalam file .m, Xcode akan secara otomatis memberikan Anda kecerdasan _variable.

Dipak Narigara
sumber
1

Memiliki garis bawah tidak hanya memungkinkan untuk menyelesaikan ivar Anda tanpa menggunakan self.member sintaks tetapi juga membuat kode Anda lebih mudah dibaca karena Anda tahu kapan suatu variabel adalah ivar (karena awalan garis bawahnya) atau argumen anggota (tanpa garis bawah) ).

Contoh:

- (void) displayImage: (UIImage *) image {

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}
Jason Fuerstenberg
sumber
Dalam contoh ini akan menyenangkan untuk melihat perbandingan penggunaan self.image (atau [gambar diri]) juga. Kapan lebih baik menggunakan self.image dan kapan lebih baik menggunakan _image?
Boeckm
2
@Boeckm: Umumnya, Anda harus menggunakan self.image, yang mengakses properti. Satu-satunya waktu Anda harus mengakses variabel instan _image,, secara langsung adalah dalam initmetode dan deallocmetode, saat memanggil metode lain mungkin berisiko (karena objek setengah diinisialisasi atau setengah-dialokasikan).
Peter Hosey
1

Ini tampaknya menjadi item "master" untuk pertanyaan tentang self.variableName vs _variablename. Apa yang mendorong saya untuk loop adalah bahwa dalam. H, saya punya:

...
@interface myClass : parentClass {
className *variableName;    // Note lack of _
}

@property (strong, nonatomic) className  *variableName;
...

Ini mengarah ke self.variableName dan _variableName menjadi dua variabel berbeda dalam .m. Yang saya butuhkan adalah:

...
@interface myClass : parentClass {
className *_variableName;    // Note presence of _
}

@property (strong, nonatomic) className  *variableName;
...

Kemudian, dalam class '.m, self.variableName dan _variableName setara.

Yang saya masih belum jelas adalah mengapa banyak contoh masih berfungsi, bahkan sulit ini tidak dilakukan.

sinar

RayInNoIL
sumber
0

alih-alih menggarisbawahi Anda dapat menggunakan nama self.variable atau Anda dapat mensintesis variabel untuk menggunakan variabel atau outlet tanpa menggarisbawahi.

SARATH SASI
sumber
2
jika Anda hanya perlu variabel di kelas yang sama hanya mendeklarasikannya dalam file .m itu sendiri maka itu akan memungkinkan Anda untuk memanggil tanpa diri atau garis bawah
Ansal Antony
0

Hilang dari jawaban lain adalah bahwa menggunakan _variablemencegah Anda mengetik tanpa sadarvariable dan mengakses ivar daripada properti (mungkin dimaksudkan).

Kompiler akan memaksa Anda untuk menggunakan salah satu self.variableatau _variable. Menggunakan garis bawah membuat tidak mungkin untuk mengetik variable, yang mengurangi kesalahan programmer.

- (void)fooMethod {

    // ERROR - "Use of undeclared identifier 'foo', did you mean '_foo'?"
    foo = @1;

    // So instead you must specifically choose to use the property or the ivar:

    // Property
    self.foo = @1;

    // Ivar
    _foo = @1;

}
pkamb
sumber