Yanıtlar:
void *
"türlenmemiş / bilinmeyen içerikli bazı rastgele yığın belleklere referans"
id
"Sınıfı bilinmeyen bazı rastgele Objective-C nesnelerine başvuru"
Ek anlamsal farklılıklar vardır:
Yalnızca GC veya GC Destekli modlar altında, derleyici tür referansları için yazma engelleri gönderir id
, ancak tür için değil void *
. Yapıları bildirirken, bu kritik bir fark olabilir. İVars gibi bildirmek , aslında bir nesne ise void *_superPrivateDoNotTouch;
nesnelerin erken biçilmesine neden olur _superPrivateDoNotTouch
. Bunu yapma.
void *
tür referansı üzerinde bir yöntemi çağırmaya çalışmak derleyici uyarısını engeller.
bir id
tür üzerinde bir yöntem çağırmaya çalışmak , yalnızca çağrılan yöntem @interface
derleyici tarafından görülen hiçbir bildirimde bildirilmemişse uyarır .
Dolayısıyla, bir nesneye asla bir void *
. Benzer şekilde, id
bir nesneyi belirtmek için yazılan bir değişken kullanmaktan kaçınılmalıdır . Yapabileceğiniz en spesifik sınıf tipi referansı kullanın. Hatta NSObject *
daha iyi olduğu id
derleyici, en azından, bu referansa karşı metot çağrımı daha iyi bir kanıt sağlar, çünkü.
Bir yaygın ve geçerli kullanımı, void *
başka bir API'den geçirilen opak bir veri referansıdır.
Şu sortedArrayUsingFunction: context:
yöntemi düşünün NSArray
:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
Sıralama işlevi şu şekilde bildirilir:
NSInteger mySortFunc(id left, id right, void *context) { ...; }
Bu durumda, NSArray yalnızca context
argüman olarak geçtiğiniz her şeyi yönteme context
argüman olarak iletir. NSArray söz konusu olduğunda, işaretçi boyutundaki verilerin opak bir parçası ve istediğiniz herhangi bir amaç için kullanmakta özgürsünüz.
Dilde bir kapatma türü özelliği olmadan, bir işlevle bir veri yığınını taşımanın tek yolu budur. Misal; mySortFunc () öğesinin koşullu olarak büyük / küçük harfe duyarlı veya büyük / küçük harfe duyarlı olmamasını istiyorsanız, yine de iş parçacığı için güvenli olsa da, büyük / küçük harf duyarlı göstergeyi bağlamda geçirirsiniz, büyük olasılıkla içeri ve dışarı çıkarken döküm yapar.
Kırılgan ve hata eğilimli, ancak tek yol.
Bloklar bunu çözer - Bloklar C için kapanır. Clang'da mevcuttur - http://llvm.org/ ve Kar Leoparı'nda yaygındır ( http://developer.apple.com/library/ios/documentation/Performance /Referans/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf ).
id
yanıtın neye yanıt verdiği hakkında hiçbir varsayım yapılamaz . Bir id
, kendiliğinden olmayan bir sınıf örneğine kolayca başvurabilir NSObject
. Ancak pratik olarak, ifadeniz gerçek dünyadaki davranışlarla en iyi şekilde eşleşir; <NSObject>
uygulanmayan sınıfları Foundation API ile karıştıramazsınız ve çok uzağa gidemezsiniz , bu kesinlikle kesin!
id
ve Class
türleri ARC altında korunabilir nesne işaretçisi olarak kabul edilmektedir . Dolayısıyla, varsayım en azından ARC altında doğrudur.
id, objid C nesnesinin bir göstergesidir; burada void *, herhangi bir şeyin göstergesidir.
id ayrıca bilinmeyen mthod'ları çağırmayla ilgili uyarıları da kapatır, örneğin:
[(id)obj doSomethingWeirdYouveNeverHeardOf];
bilinmeyen yöntemler hakkında olağan uyarı vermeyecektir. Nesnel sıfır değilse veya gerçekten bu yöntemi uygulamadığı sürece, çalışma zamanında bir istisna oluşturacaktır.
Genellikle NSObject*
veya en azından geri döndürülen nesnenin bir Kakao nesnesi olduğunu onaylayan veya id<NSObject>
tercih ettiğiniz şekilde id
, üzerinde tutma / bırakma / otomatik serbest bırakma gibi yöntemleri güvenle kullanabilirsiniz.
Often you should use NSObject*
yerine katılmıyorum id
. Belirterek NSObject*
aslında nesnenin bir NSObject olduğunu açıkça söylüyorsunuz. Nesneye yapılan herhangi bir yöntem çağrısı bir uyarı ile sonuçlanır, ancak bu nesne gerçekten yöntem çağrısına yanıt verdiği sürece çalışma zamanı istisnası yoktur. Uyarı açıkçası sinir bozucu yani id
daha iyidir. id<MKAnnotation>
Kabadan, örneğin bu durumda nesne ne olursa olsun, MKAnnotation protokolüne uyması gerektiğini söyleyerek daha spesifik olabilirsiniz .
Bir yöntemin bir dönüş türü id
varsa, herhangi bir Objective-C nesnesi döndürebilirsiniz.
void
yani yöntem hiçbir şey döndürmez.
void *
sadece bir işaretçi. İşaretçinin işaret ettiği adresteki içeriği düzenleyemezsiniz.
id
Objective-C nesnesinin bir göstergesidir. void *
her şeyin bir göstergesidir . Bunun void *
yerine kullanabilirsiniz id
, ancak hiçbir şey için derleyici uyarıları almayacağınız için önerilmez.
Stackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobject ve unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs adresini görmek isteyebilirsiniz. -id.html .
void *
yazılan değişkenler kesinlikle yöntem çağrılarının hedefi olabilir - bu bir uyarı değil, bir uyarıdır. Sadece bunu yapabileceğini sözlerine: int i = (int)@"Hello, string!";
ve takip: printf("Sending to an int: '%s'\n", [i UTF8String]);
. Bu bir uyarı değildir, bir hata değildir (ve tam olarak önerilmez veya taşınabilir değildir). Ancak bu şeyleri yapabilmenizin nedeni tüm temel C.
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
Yukarıdaki kod objc.h'den alınmıştır, bu nedenle id, objc_object yapısının bir örneğidir ve isa işaretçisi herhangi bir Objective C Sınıfı nesnesine bağlanabilirken, void * yalnızca türlenmemiş bir işaretçidir.
Anladığım kadarıyla id, bir nesnenin işaretçisini temsil ederken void * gerçekten kullanmak istediğiniz türe yönlendirdiğiniz sürece gerçekten herhangi bir şeye işaret edebilir
Daha önce söylenenlere ek olarak, koleksiyonlarla ilgili nesneler ve işaretçiler arasında bir fark vardır. Örneğin, NSArray'e bir şey koymak istiyorsanız, bir nesneye ("id" türünde) ihtiyacınız vardır ve orada ham veri işaretçisini ("void *" türünde) kullanamazsınız. Bir koleksiyon içinde kullanmak için "id" türüne [NSValue valueWithPointer:rawData]
dönüştürmek void *rawDdata
için kullanabilirsiniz . Genel olarak "id" daha esnektir ve ona bağlı nesnelerle ilgili daha fazla anlambilime sahiptir. Burada Objective C'nin id türünü açıklayan daha fazla örnek var .
id
cevap vermek için varsayılır-retain
ve-release
oysa avoid*
callee tamamen opak.-performSelector:withObject:afterDelay:
(Nesneyi korur) seçeneğine rastgele bir işaretçi+[UIView beginAnimations:context:]
iletemezsiniz ve bağlamı koruyacağını varsayamazsınız (animasyon delegesi içeriğin sahipliğini korumalıdır; UIKit animasyon delegesini korur).