SORU
10 Kasım 2010, ÇARŞAMBA


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
5 ŞUBAT 2013, Salı


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.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BigDawsTv

    BigDawsTv

    20 HAZİRAN 2012
  • Ciaran Blumenfeld

    Ciaran Blume

    20 NİSAN 2009
  • John Lynn

    John Lynn

    8 Ocak 2010