Evet, instancetype
geçerli olduğu her durumda kullanmanın faydaları vardır . Daha ayrıntılı olarak açıklayacağım, ancak şu cesur ifadeyle başlayayım: Uygun instancetype
olduğunda kullanın , yani bir sınıf aynı sınıfın bir örneğini döndürdüğünde.
Aslında, Apple şu anda bu konuda şunları söylüyor:
Kodunuzda, id
dönüş değeri olarak oluşumlarını instancetype
uygun olanlarla değiştirin. Bu genellikle init
yöntemler ve sınıf fabrikası yöntemleri için geçerlidir. Derleyici otomatik olarak “alloc” “init” veya “yeni” ile başlayan ve bir dönüş türü yöntemleri dönüştürür olsa id
geri dönüşü instancetype
, diğer metotların dönüştürmez. Amaç-C kuralı instancetype
tüm yöntemler için açıkça yazmaktır .
Yoldan çekilip, bunun neden iyi bir fikir olduğunu açıklayalım.
İlk olarak, bazı tanımlar:
@interface Foo:NSObject
- (id)initWithBar:(NSInteger)bar; // initializer
+ (id)fooWithBar:(NSInteger)bar; // class factory
@end
Sınıf fabrikası için her zaman kullanmalısınız instancetype
. Derleyici otomatik olarak dönüştürmez id
için instancetype
. Bu id
genel bir nesne. Ancak bunu bir instancetype
derleyici yaparsanız , yöntemin ne tür bir nesne döndürdüğünü bilir.
Bu akademik bir sorun değil . Örneğin [[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]
, Mac OS X'te bir hata oluşturur ( yalnızca ) Eşleşmeyen sonuç, parametre türü veya niteliklerle bulunan 'writeData:' adlı birden çok yöntem bulunur . Bunun nedeni hem NSFileHandle hem de NSURLHandle'ın a writeData:
. Yana [NSFileHandle fileHandleWithStandardOutput]
getiriler bir id
, derleyici hangi sınıf kesin değildir writeData:
çağrıldığı.
Aşağıdakilerden birini kullanarak bu soruna geçici bir çözüm bulmanız gerekir:
[(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData];
veya:
NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardOutput];
[fileHandle writeData:formattedData];
Tabii ki, daha iyi bir çözüm fileHandleWithStandardOutput
geri dönen olarak ilan etmektir instancetype
. Sonra oyuncu kadrosu veya ödev gerekli değildir.
(Yalnızca iOS'taki, bu örnek, bir hata üretmek olmayacak Not NSFileHandle
bir sağlar writeData:
vardır. Diğer örnekler, örneğin, mevcut length
bir döndüren CGFloat
gelen UILayoutSupport
ancak bir NSUInteger
mesafede NSString
).
Not : Bunu yazdığım için, macOS başlıkları bir NSFileHandle
yerine döndürülecek şekilde değiştirildi id
.
Başlatıcılar için daha karmaşıktır. Bunu yazdığınızda:
- (id)initWithBar:(NSInteger)bar
… Derleyici bunun yerine yazmış gibi davranacaktır:
- (instancetype)initWithBar:(NSInteger)bar
Bu ARC için gerekliydi. Bu, Clang Dil Uzantıları İlgili sonuç türlerinde açıklanmaktadır . Bu yüzden insanlar sana kullanmanın gerekli olmadığını söyleyecekler instancetype
, ama ben bunu yapman gerektiğini savunuyorum. Bu cevabın geri kalanı bununla ilgilidir.
Üç avantajı vardır:
- Açık. Kodunuz başka bir şey yerine, söylediklerini yapıyor.
- Desen. Önemli olan zamanlarda var olan iyi alışkanlıklar inşa ediyorsunuz.
- Tutarlılık. Kodunuzda bir miktar tutarlılık belirlediniz, bu da onu daha okunabilir hale getirdi.
Açık
Bir ülkeden dönmenin teknik bir yararı olmadığı doğrudur . Derleyici otomatik dönüştürür çünkü Ama bu To . Bu tuhaflığa güveniyorsun; bir döndürme yazdığını yazarken , derleyici bunu bir döndürme işlemi olarak yorumluyor .instancetype
init
id
instancetype
init
id
instancetype
Bunlar derleyiciye eşdeğerdir :
- (id)initWithBar:(NSInteger)bar;
- (instancetype)initWithBar:(NSInteger)bar;
Bunlar gözlerinizle eşdeğer değil. En iyi ihtimalle, farkı görmezden gelmeyi ve üzerinde kaymayı öğreneceksiniz. Bu görmezden gelmeyi öğrenmen gereken bir şey değil.
Desen
Hiçbir farkı olmasa da init
ve diğer yöntemler, orada olan bir sınıf fabrika tanımlayan en kısa sürede bir fark.
Bu ikisi eşdeğer değildir:
+ (id)fooWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
İkinci formu istiyorsunuz. Bir kurucunun instancetype
dönüş türü olarak yazmaya alışkınsanız , her seferinde doğru şekilde alırsınız.
Tutarlılık
Son olarak, hepsini bir araya getirdiğinizi düşünün: bir init
fonksiyon ve aynı zamanda bir sınıf fabrikası istiyorsunuz .
Eğer kullanırsanız id
için init
, böyle koduyla sonuna kadar:
- (id)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
Ancak kullanırsanız instancetype
, bunu elde edersiniz:
- (instancetype)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
Daha tutarlı ve daha okunabilir. Aynı şeyi geri getiriyorlar ve şimdi bu açık.
Sonuç
Eski derleyiciler için kasıtlı olarak kod yazmadığınız sürece, instancetype
uygun olduğunda kullanmalısınız .
Geri dönen bir mesaj yazmadan önce tereddüt etmelisiniz id
. Kendinize sorun: Bu, bu sınıfın bir örneği mi? Eğer öyleyse, bu bir instancetype
.
Kesinlikle geri dönmeniz gereken durumlar var id
, ancak muhtemelen instancetype
çok daha sık kullanacaksınız .