Kakao objektif-c sınıfındaki bir değişkenin önündeki alt çizgi nasıl çalışır?


157

Birkaç iPhone örneğinde, özelliklerin değişkenin önünde bir alt çizgi _ kullandığını gördüm. Bunun ne anlama geldiğini bilen var mı? Veya nasıl çalışır?

Kullandığım arayüz dosyası şöyle:

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

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

Yukarıdakilerin tam olarak ne yaptığından emin değilim ama görev adını ayarlamaya çalıştığımda:

aMission.missionName = missionName;

Hatayı alıyorum:

'misyonAdı' üyesi için yapı veya birlik olmayan bir şeyde istek

Yanıtlar:


97

İvarlarınız için alt çizgi önekini kullanırsanız (bu, ortak bir kongre değil, kullanışlı bir şeyden başka bir şey değildir), otomatik olarak oluşturulan erişimcinin (özellik için) hangi ivar'ın kullanılacağını bilmesi için 1 ekstra şey yapmanız gerekir. Özellikle, uygulama dosyanızda synthesizeşöyle görünmelisiniz:

@synthesize missionName = _missionName;

Daha genel olarak, bu:

@synthesize propertyName = _ivarName;

78
otomatik sentezleme özellikleri ile bu artık gerekli değildir. Xcode, @property xxxx'i sahne arkasında _xxxx adlı bir ivar ile sentezler. Temiz.
LearnCocos2D

@ LearnCocos2D Merhaba! Burada iOS'a yeni başlayan bir kişi ve açıklığa kavuşturmam gereken bir şey var. Bütün bu zaman boyunca ne yaptığını beyan oldu property.h dosyasında ve kullanma .m yuh ben erişimde self, şöyle self.someProperty. Bu doğru yol mu? Yoksa ivars kodunda mı kullanmalıyım?
Isuru

Ivar'ı ayarlamak özellik ayarlayıcıyı çalıştırmaz - her özel durum için bunun iyi bir fikir olup olmadığına siz karar verirsiniz
LearnCocos2D

Noob sorusu: Neden ivarları doğrudan kullanmıyorsunuz? Neden ivar tutmak için ayrı bir var beyan etmeliyim?
Allen

1
@Allen, sorunuzu doğru anlarsam: Bildirdiğiniz ayrı değişken, gerçek değişkenin bir göstergesidir. Bu, birkaç nedenden dolayı (bildiğim) önemlidir: İlk olarak, bir işaretçiyi bir işleve geçirdiğinizde değerini çoğaltmazsınız. Sadece fonksiyona kullanılacak değeri nerede bulacağınızı söylüyorsunuz. Bu, kullanılan belleğinizi düşük tutmanıza yardımcı olur (ve ayrıca, Java'da bulacağınız 'çöp toplama' yokluğunda önemli olan bellek tahsisi ve dağıtılması ile yardımcı olur)
David Sigley

18

Bu sadece okunabilirlik için bir ibadettir, derleyiciye özel bir şey yapmaz. Kullanıcıların özel örnek değişkenlerde ve yöntem adlarında kullandığını göreceksiniz. Apple aslında alt çizgiyi kullanmamanızı önerir (eğer dikkatli değilseniz süper sınıfınızdaki bir şeyi geçersiz kılabilirsiniz), ancak bu tavsiyeyi görmezden gelmek konusunda kendinizi kötü hissetmemelisiniz. :)


19
Anladığım kadarıyla Apple, yöntem adlarında alt çizgi önekinin kullanılmasını öneriyor (bunu özel yöntemler için bir kongre olarak ayırırlar), ancak örnek değişken adları hakkında böyle bir öneri yoktur.
Kelan

9
@Kelan Aslında, Apple bunu yapmaya teşvik ediyor : "Genellikle örnek değişkenlerine doğrudan erişmemelisiniz, bunun yerine erişimci yöntemlerini kullanmalısınız (örnek değişkenlerine doğrudan init ve dealloc yöntemlerinde erişmelisiniz). alt çizgi (_) olan değişken adları, örneğin: \ @impistan MyClass {BOOL _showsTitle;} "
dmirkitanov

Aslında Apple'ın bunu yapmaya teşvik ettiğini düşünmüyorum, çünkü iOS Geliştirici Kütüphanesi'ndeki tüm kendi örnek kodlarında ( ) yok. Apple ayrıca, bunu rezerve ettiklerini söylüyor, bu da dahili olarak UIKit vb.Gibi kendi çerçeveleri için kullandıkları anlamına geliyor. Bu yüzden dikkatsizce kullanmamalıyız. Ama görüyorum ki, @kelan'a verdiğiniz linkte. Aslında "revizyon geçmişinde" ( ) kullanılmasının "uygun" olduğunu söylüyorlar . Ben yorumlamak istediğimiz gibi kullanabileceğimiz gibi.
WYS

Apple'ın yöntem adları için alt çizgi önekini kullanmamayı söyleyen belgeleri burada .
ThomasW

9

Gördüğüm tek yararlı amaç, yerel değişkenler ile üye değişkenler arasında yukarıda belirtildiği gibi ayrım yapmaktır, ancak bu gerekli bir kural değildir. Bir @property ile eşleştirildiğinde, sentez ifadelerinin ayrıntı düzeyini artırır @synthesize missionName = _missionName;ve her yerde çirkin olur.

Alt çizgiyi kullanmak yerine, çakışmayan yöntemlerde açıklayıcı değişken adları kullanın. Çakışmaları gerektiğinde, yöntem içindeki değişken adının birden çok yöntemle kullanılabilecek üye değişkeni değil alt çizgisi olmalıdır . Bunun yararlı olduğu tek yer, bir ayarlayıcı veya bir init yöntemidir. Buna ek olarak, @synthesize deyimini daha özlü hale getirecektir.

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

Düzenleme: Otomatik sentez en son derleyici özelliği ile, şimdi ivar için alt çizgi kullanın (nadir durumlarda ben otomatik sentez ne yapmak için bir ivar kullanmanız gerekir.


Tam tersi. özel değişkenin altı çizilidir. mülkiyet değil. ve onları sentezleyerek onları birleştirirsiniz.
Justin

Tam olarak açıkladığım gibi, ancak "özel değişken" yerine "üye değişken" olarak adlandırdım.
Peter DeWeese

Ah! Bu sorun istiyor… otomatik sentez ivar _myString yapar, bu da ayarlayıcının çalışmadığı anlamına gelir (çünkü ivar'ınızı method parametresinden söyleyemez).
geowar

Doğru, bu yüzden elma otomatik sentez eklediğinde düzenlemeyi sonuna ekledim.
Peter DeWeese

5

Gerçekten hiçbir şey ifade etmiyor, sadece bazı insanların üye değişkenleri yerel değişkenlerden ayırmak için kullandıkları bir kural.

Hata gelince, aMission yanlış tipe sahip gibi görünüyor. Beyanı nedir?


IDE'lerde zeka ile yaygındır; üye / modül / sınıf değişkenlerinizi listenin en üstünde gösterecektir. Başka bir yaygın ön ek "m_" dir
STW

1
bir şey ifade etmiyorsa, yukarıdaki örnekte olduğu gibi _missionName ve missionName arasında nasıl geçiş yapabilirsiniz? Beyanım şöyle görünüyor: Mission * aMission = [[Mission fare] init]; aMission.missionName = @ "bir görev";
Atma

1
Biri bir örnek değişkeni, diğeri bir özelliktir. AMission.missionName gibi sözdizimiyle örnek değişkenlere erişemezsiniz, çünkü sözdizimi işaretçilerle çalışmaz.
Chuck

Ayrıca, bir Mission nesnesi üzerinde çalışmaya çalıştığınızı, ancak missionName özelliğiyle birlikte gönderdiğiniz arabirimin bir MissionCell olduğunu unutmayın.
smorgan

2

Bu sadece sentezleme özelliklerinin adlandırma kuralları içindir.

.M dosyasındaki değişkenleri sentezlediğinizde, Xcode size otomatik olarak _değişken zeka sağlayacaktır.


1

Alt çizgiye sahip olmak, ivar'larınızı self kullanmaya başvurmadan çözmeyi mümkün kılmaz. sözdizimini kalmaz, aynı zamanda değişkenin bir ivar (alt çizgi öneki nedeniyle) veya üye argümanı (alt çizgi yok) olduğunu bildiğiniz için kodunuzu daha okunabilir hale getirir. ).

Misal:

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

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}

Bu örnekte self.image (veya [self image]) kullanımının bir karşılaştırmasını görmek de hoş olacaktır. Self.image ne zaman daha iyi ve _image ne zaman daha iyi?
Boeckm

2
@Boeckm: Genellikle, self.imageözelliğe erişen kullanmalısınız . Örnek değişkenine erişmeniz gereken tek zaman _image, doğrudan inityöntemler içinde ve deallocyöntemdir, başka bir yöntem çağrıldığında riskli olabilir (nesne yarı başlatılmış veya yarı ayrılmış olduğundan).
Peter Hosey

1

Bu, self.variableName ve _variablename ile ilgili sorular için "ana" öğe gibi görünüyor. Beni bir döngü için atmış olan şey, .h'de:

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

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

Bu, self.variableName ve _variableName öğelerinin .m içinde iki farklı değişken olmasına yol açar. İhtiyacım olan şey:

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

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

Daha sonra '.m sınıfında self.variableName ve _variableName eşdeğerdir.

Hala net olmadığım şey, bunun yapılmaması zor olsa bile, birçok örneğin neden hala çalıştığıdır.

ışın


0

alt çizgi yerine self.variable adını kullanabilir veya alt çizgi olmadan değişkeni veya çıkışı kullanmak için değişkeni sentezleyebilirsiniz.


2
Yalnızca aynı sınıfta değişkeni gerekirse tam o .m dosyasında kendisini beyan Eğer kendini ne de çizgi olmadan çağırmak sağlayacak
Ansal Antony

0

Diğer cevaplardan eksik olması, kullanmanın _variablekayıtsız bir şekilde yazmanızı engellemesidir.variable , kullanımın (varsayılan olarak amaçlanan) özellikten ziyade ve erişmenizi .

Derleyici sizi ya self.variableda kullanmaya zorlar _variable. Alt çizgi kullanmak variable, programcı hatalarını azaltan yazmayı imkansız hale getirir .

- (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;

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.