Objective-C'deki Salt Okunur Özellikler?


94

Arayüzümde aşağıdaki gibi salt okunur bir özellik beyan ettim:

 @property (readonly, nonatomic, copy) NSString* eventDomain;

Belki özellikleri yanlış anlıyorum, ancak bunu olarak ilan ettiğinizde readonly, oluşturulan ayarlayıcıyı implementasyon ( .m) dosyası içinde kullanabilirsiniz , ancak harici varlıklar değeri değiştiremez diye düşündüm . Bu SO sorusu bunun olması gerektiğini söylüyor. Peşinde olduğum davranış bu. Bununla birlikte, eventDomaininit yöntemimin içine ayarlamak için standart ayarlayıcı veya nokta sözdizimini kullanmaya çalışırken , bu bana bir unrecognized selector sent to instance.hata veriyor . Tabii ki @synthesizemülk sahibi oluyorum . Bunu şu şekilde kullanmaya çalışıyorum:

 // inside one of my init methods
 [self setEventDomain:@"someString"]; // unrecognized selector sent to instance error

Öyleyse readonlybir mülk hakkındaki beyanı yanlış mı anlıyorum ? Yoksa başka bir şey mi oluyor?

Yanıtlar:


118

Derleyiciye ayrıca bir ayarlayıcı istediğinizi söylemeniz gerekir. Yaygın bir yol, onu .m dosyasındaki bir sınıf uzantısına koymaktır :

@interface YourClass ()

@property (nonatomic, copy) NSString* eventDomain;

@end

22
Bu bir kategori değil. Bu bir sınıf uzantısıdır (Eiko'nun dediği gibi). Benzer amaçlar için kullanılsalar da belirgin şekilde farklıdırlar. Örneğin, yukarıdakileri gerçek bir kategoride yapamazsınız.
bbum

2
Sınıf uzantısı özelliklerine sahip bir sınıftan miras alan bir sınıfın bunları görmeyeceğini fark ettim. yani kalıtım yalnızca harici arabirimi görür. onaylamak?
Yogev Shelly

5
Bu pek adil değil. Farklı olabilir, ancak "Anonim kategori" olarak biliniyor
MaxGabriel

3
Bu, operasyonun genel arayüzdeki ilk bildirimine ek mi? Yani, bu sınıf uzantısı bildirimi? İçindeki ilk bildirimi geçersiz kılar .hmı? Aksi takdirde, bunun bir kamu düzenleyicisini nasıl ifşa edeceğini anlamıyorum. Teşekkürler
Madbreaks

4
@Madbreaks Ektir, ancak .m dosyasındadır. Böylece derleyici, onu o sınıf için yeniden yazmayı bilir, ancak harici kullanım beklendiği gibi salt okunur olarak sınırlıdır.
Eiko

38

Eiko ve diğerleri doğru cevaplar verdi.

İşte daha basit bir yol: Özel üye değişkenine doğrudan erişim.

Misal

Başlık .h dosyasında:

@property (strong, nonatomic, readonly) NSString* foo;

Uygulama .m dosyasında:

// inside one of my init methods
self->_foo = @"someString"; // Notice the underscore prefix of var name.

İşte bu, tek ihtiyacın olan bu. Karışıklık yok, yaygara yok.

Detaylar

Xcode 4.4 ve LLVM Compiler 4.0'dan ( Xcode 4.4'teki Yeni Özellikler ) itibaren, diğer yanıtlarda tartışılan işlerle uğraşmanıza gerek yoktur:

  • synthesizeanahtar kelime
  • Bir değişken bildirmek
  • Özelliği uygulama .m dosyasında yeniden bildirme.

Bir özellik bildirerek sonra foo, Xcode alt çizgi bir önek ile adında bir özel üye değişkeni eklemiştir varsayabiliriz: _foo.

Özellik bildirilmişse readwrite, Xcode adlı bir alıcı yöntemi foove adlandırılmış bir ayarlayıcı oluşturur setFoo. Bu yöntemler, nokta gösterimini (my Object.myMethod) kullandığınızda örtük olarak çağrılır. Özellik bildirilmişse readonly, ayarlayıcı üretilmez. Bu, alt çizgi ile adlandırılan destek değişkeninin kendi başına salt okunur olmadığı anlamına gelir . readonlyBir ayarlayıcı yöntem bir değerini ayarlamak için nokta gösterimi kullanılarak bu nedenle sentezlenmiştir, ve daha basitçe aracı bir derleyici hatası ile başarısız olur. Derleyici, var olmayan bir yöntemi (ayarlayıcı) çağırmanızı engellediği için nokta notasyonu başarısız olur.

Bunu aşmanın en basit yolu, alt çizgi ile adlandırılan üye değişkenine doğrudan erişmektir. Bunu, altçizgi isimli değişkeni bildirmeden bile yapabilirsiniz! Xcode, bu bildirimi derleme / derleme işleminin bir parçası olarak ekliyor, bu nedenle derlenen kodunuz gerçekten değişken bildirimine sahip olacaktır. Ancak bu beyanı orijinal kaynak kod dosyanızda asla görmezsiniz. Sihir değil, sadece sözdizimsel şeker .

Kullanma self->, nesnenin / örneğin bir üye değişkenine erişmenin bir yoludur. Bunu atlayabilir ve sadece var adını kullanabilirsiniz. Ama ben + oku kullanmayı tercih ederim çünkü kodumun kendi kendini belgelemesini sağlıyor. Bu örnekte bir üye değişkeni olan self->_foobelirsizlik olmadan bildiğinizi gördüğünüzde _foo.


Bu arada, artıları ve doğrudan ivar erişimi karşı mülkiyet erişimci eksileri tartışılması Dr okumak gerekir düşünceli tedavinin tür tam olarak Matt Neuberg 'ın Programlama iOS kitabında. Okumayı ve yeniden okumayı çok yararlı buldum.


1
Belki de eklemelisiniz ki, bir üye değişkene asla doğrudan (kendi sınıfı olmadan) erişmemelisiniz! Bunu yapmak, OOP (bilgi gizleme) ihlalidir.
HAS

2
@HAS Doğru, buradaki senaryo, bu sınıfın dışından görülmeyen üye değişkenini özel olarak ayarlamaktır. Orijinal göndericinin sorusunun tüm noktası budur: Bir özelliği başkareadonly hiçbir sınıfın ayarlayamayacağı şekilde ilan etmek.
Fesleğen Bourque

Salt okunur bir mülkün nasıl oluşturulacağını öğrenmek için bu gönderiye bakıyordum. Bu benim için çalışmıyor. Başlangıçtaki değeri atamama izin veriyor, ancak _variable'ı daha sonra bir atamayla değiştirebilirim. derleyici hatası veya uyarısı oluşturmaz.
netskink

@BasilBourque Bu "kalıcılık" sorusuyla ilgili yararlı düzenleme için çok teşekkür ederiz!
GhostCat

36

Salt okunur özelliklerle çalışmanın bulduğum başka bir yolu da destek deposunu belirtmek için @synthesize kullanmaktır. Örneğin

@interface MyClass

@property (readonly) int whatever;

@end

Sonra uygulamada

@implementation MyClass

@synthesize whatever = m_whatever;

@end

m_whateverBir üye değişkeni olduğu için yöntemleriniz daha sonra ayarlanabilir .


Geçtiğimiz birkaç gün içinde fark ettiğim bir başka ilginç şey de, aşağıdaki gibi alt sınıflar tarafından yazılabilen salt okunur özellikler yapabilmenizdir:

(başlık dosyasında)

@interface MyClass
{
    @protected
    int m_propertyBackingStore;
}

@property (readonly) int myProperty;

@end

Ardından uygulamada

@synthesize myProperty = m_propertyBackingStore;

Başlık dosyasındaki bildirimi kullanır, böylece alt sınıflar, salt okunurluğunu korurken özelliğin değerini güncelleyebilir.

Yine de veri gizleme ve kapsülleme açısından biraz üzücü.


1
Tanımladığınız ilk yol, kabul edilen cevaptan daha kolaydır. Sadece bir "@synthesize foo1, foo2, foo3;" .m içinde ve her şey yolunda.
sudo

20

İOS Belgelerindeki Mevcut Sınıfları Özelleştirme konusuna bakın .

salt okunur Özelliğin salt okunur olduğunu gösterir. Salt okunur olarak belirtirseniz, @ uygulamada yalnızca bir alıcı yöntemi gerekir. Uygulama bloğunda @ synthesize kullanırsanız, yalnızca getter yöntemi sentezlenir. Ayrıca, nokta sözdizimini kullanarak bir değer atamaya çalışırsanız, bir derleyici hatası alırsınız.

Salt okunur özelliklerin yalnızca bir alıcı yöntemi vardır. Yine de destek ivarını doğrudan mülkün sınıfı içinde veya anahtar değeri kodlamasını kullanarak ayarlayabilirsiniz.


9

Diğer soruyu yanlış anlıyorsunuz. Bu soruda şu şekilde beyan edilen bir sınıf uzantısı vardır:

@interface MYShapeEditorDocument ()
@property (readwrite, copy) NSArray *shapesInOrderBackToFront;
@end

Bu, yalnızca sınıfın gerçeklemesinde görülebilen ayarlayıcıyı oluşturan şeydir. Eiko'nun dediği gibi, derleyiciye yalnızca sınıf içinde bir ayarlayıcı oluşturmasını söylemek için bir sınıf uzantısı bildirmeniz ve özellik bildirimini geçersiz kılmanız gerekir.


5

En kısa çözüm:

Sınıfım.h

@interface MyClass {

  int myProperty;

}

@property (readonly) int myProperty;

@end

Sınıfım.h

@implementation MyClass

@synthesize myProperty;

@end

2

Bir özellik salt okunur olarak tanımlanırsa, bu, sınıfa dahili olarak veya diğer sınıflardan harici olarak kullanılabilecek bir ayarlayıcı olmayacağı anlamına gelir. (yani: Eğer mantıklıysa bir "alıcıya" sahip olacaksınız.)

Seslerinden, özel olarak işaretlenmiş normal bir okuma / yazma özelliği istiyorsunuz, bunu arayüz dosyanızda aşağıdaki gibi özel olarak ayarlayarak elde edebilirsiniz:

@private
    NSString* eventDomain;
}
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.