Neden sıfır / BOŞ blok çalıştırıldığında otobüs hatalara neden?
“Blok” özelliği yoktur blokları otobüs hatalarına neden olan Objective-C blokları bir sürü kullanarak ve yakında fark etmeye başladım son sürümleri eklendi: bayıldım
typedef void (^SimpleBlock)(void);
SimpleBlock aBlock = nil;
aBlock(); // bus error
Bu nil nesnelere mesajları yok sayan Objective-C: her zamanki davranış karşı gitmek gibi görünüyor
NSArray *foo = nil;
NSLog(@"%i", [foo count]); // runs fine
Bu nedenle bir blok kullanmadan önce her zamanki nil onay çare buldum
if (aBlock != nil)
aBlock();
Ya da kukla blokları kullanın:
aBlock = ^{};
aBlock(); // runs fine
Başka bir seçenek var mı? Nil bloklar sadece bir nop olamazdı neden bir nedeni var mı?
CEVAP
Bu biraz daha açıklamak için, daha eksiksiz bir cevap istiyorum. Önce şu kodu ele alalım:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
void (^block)() = nil;
block();
}
Eğer bu çalıştırırsanız, o zaman böyle bir şey (32-bit mimarisi üzerinde çalışma yaparken önemli olan) görünüyor block()
satırında bir kaza görürsünüz.
EXC_BAD_ACCESS (code=2, 0xc=Adres)
, Bu neden böyle? - 0xc
en önemli parçasıdır. Kaza işlemci bellek adresine bilgileri 0xc
okumak için çalıştı anlamına gelir. Bu neredeyse kesinlikle yapmak tamamen yanlış bir şey. Oradan birşey olası değil. Ama neden bu hafıza konumuna okumayı denedin mi? Bence, bir blok aslında kaputun altında inşa şeklinden dolayı.
Bir blok tanımlandığında, derleyici aslında yığını, bu formun üzerinde bir yapı oluşturur
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
Blok daha sonra bu yapı için bir işaretçi. , invoke
, bu yapının dördüncü üyesi ilginçtir. Bir işlev işaretçisi, blok uygulaması yapıldığı kod işaret etmektedir. İşlemci bloğu çağrıldığında kod atlamak için çalışır. invoke
üye önce yapısı içinde bayt sayısını da sayarsak, 12 ondalık veya onaltılık C olduğunu göreceksiniz dikkat edin.
Bir blok çalıştırıldığında, işlemci bloğunun adresini alır, 12 ekler ve değerini bellek adrese düzenlenen yüklemeye çalışır. O zaman bu adrese atlamak için çalışır. Ama eğer blok nil ise 17 ** Adres okumak için çalışacağız. Bu duff adresi, açıkça, ve bölümleme hatası alıyorum.
Şimdi böyle bir kaza yerine sessizce gibi Objective-C mesaj diyor bir başarısız olmalı nedeni gerçekten tasarım bir seçimdir. Derleyici bloğu çağırmak için nasıl karar verme işi olduğundan, bir blok her yerde kod kontrol çağrılır nil enjekte etmek olurdu. Bu artışın boyutu kod ve kötü performansa neden olacaktır. Başka bir seçenek yoktur, denetimi bir tramplen kullanmak olacaktır. Ancak bu da performans cezaya tabidir. Objective-C iletileri zaten aslında çağrılacak yöntemi bakmaları gerekir çünkü bir trambolin geçmesi. Çalışma yöntemleri tembel enjeksiyon yöntemi ve uygulamaları değiştirmek için izin verir, zaten bir trambolin zaten geçiyor. Nil kontrol işini yapanlar ekstra ceza bu durumda önemli değildir.
Biraz gerekçesini açıklamak için yardımcı olur umarım.
Daha fazla bilgi için, benim 18* posts*bakın.
Neden "her blok deneyin" sara...
Neden kullan try {} finally {} boş den...
Neden bir nihayet döndü değişken değiş...
ekran giriş:blok blok değil, neden olm...
Neden boş blok kötü bir fikir yakalama...