Kelas dasar asli Swift atau NSObject


105

Saya menguji beberapa isa swizzling dengan Swift, dan menemukan bahwa itu hanya berfungsi ketika NSObject adalah kelas super (langsung atau lebih jauh), atau dengan menggunakan dekorasi '@objc'. Jika tidak, itu akan mengikuti gaya statis- dan vtable-dispatch, seperti C ++.

Apakah normal untuk menentukan kelas Swift tanpa kelas dasar Cocoa / NSObject? Jika saya khawatir, ini berarti mengabaikan banyak dinamisme Objective-C, seperti intersepsi metode dan introspeksi run-time.

Perilaku waktu proses dinamis berada di jantung fitur seperti pengamat properti, Data Inti, Pemrograman Berorientasi Aspek , Perpesanan Pesanan Tinggi , kerangka kerja analitis & logging, dan sebagainya.

Menggunakan gaya pemanggilan metode Objective-C menambahkan sekitar 20 operan kode mesin ke pemanggilan metode, jadi dalam situasi tertentu ( banyak panggilan ketat ke metode dengan badan kecil ) pengiriman statis dan vtable gaya C ++ dapat bekerja lebih baik.

Tetapi mengingat aturan umum 95-5 ( 95% peningkatan kinerja berasal dari penyetelan 5% kode ), bukankah masuk akal untuk memulai dengan fitur dinamis yang kuat dan mengeras jika diperlukan?


Terkait: Apakah Swift mendukung pemrograman berorientasi aspek? stackoverflow.com/a/24137487/404201
Jasper Blues

Jawaban:


109

Kelas Swift yang merupakan subkelas dari NSObject:

  • adalah kelas Objective-C itu sendiri
  • digunakan objc_msgSend()untuk panggilan ke (sebagian besar) metode mereka
  • menyediakan metadata runtime Objective-C untuk (sebagian besar) implementasi metode mereka

Kelas Swift yang bukan merupakan subkelas dari NSObject:

  • adalah kelas Objective-C, tetapi hanya mengimplementasikan beberapa metode untuk kompatibilitas NSObject
  • jangan gunakan objc_msgSend()untuk panggilan ke metode mereka (secara default)
  • tidak menyediakan metadata waktu proses Objective-C untuk implementasi metode mereka (secara default)

Subclassing NSObject di Swift memberi Anda fleksibilitas runtime Objective-C tetapi juga kinerja Objective-C. Menghindari NSObject dapat meningkatkan kinerja jika Anda tidak membutuhkan fleksibilitas Objective-C.

Edit:

Dengan Xcode 6 beta 6, atribut dinamis muncul. Ini memungkinkan kita untuk menginstruksikan Swift bahwa suatu metode harus menggunakan pengiriman dinamis, dan oleh karena itu akan mendukung intersepsi.

public dynamic func foobar() -> AnyObject {
}

1
Jenis pengiriman apa yang digunakan Swift selain objc_msgSend? Apakah itu statis?
Tagihan

12
Swift dapat menggunakan objc_msgSend dispatch, virtual table dispatch, direct dispatch, atau inlining.
Greg Parker

statis: kurang dari 1.1ns. vtable 1.1ns, msgSend 4.9ns. . (Tergantung pada hardware tentunya). . Tampaknya Swift 'murni' membuat bahasa yang bagus untuk pemrograman tingkat sistem, tetapi untuk aplikasi, saya enggan melepaskan fitur dinamis, meskipun saya akan senang jika mereka pindah ke kompiler seperti-dalam Koleksi Sampah vs ARC. . . Saya pernah mendengar bahwa pengiriman statis memungkinkan prediksi cabang yang lebih baik (dan dengan demikian kinerja) pada sistem multi-inti. Benar?
Jasper Blues

"Kelas Swift yang bukan subkelas dari NSObject adalah kelas Objective-C" - dapatkah Anda memberikan tautan ke tempat Anda menemukan pernyataan itu?
Matt S.

1
Jadi secara ringkas, saya sebaiknya hanya membuat subclass NSObject di Swift jika saya perlu berkomunikasi dengan kode Objective C?
MobileMon

14

Saya juga menemukan bahwa jika mendasarkan kelas Swift pada NSObject, saya melihat beberapa perilaku run-time yang tidak terduga yang dapat menyembunyikan bug pengkodean. Berikut ini contohnya.

Dalam contoh ini, di mana kita tidak mendasarkan pada NSObject, kompilator dengan benar menemukan kesalahan dalam testIncorrect_CompilerShouldSpot, melaporkan "... 'MyClass' tidak dapat diubah menjadi 'MirrorDisposition'"

class MyClass {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

Dalam contoh ini, di mana kami mendasarkan pada NSObject , compiler tidak melihat kesalahan dalam testIncorrect_CompilerShouldSpot:

class myClass : NSObject {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

Saya kira moralnya adalah, hanya berdasarkan NSObject di mana Anda benar-benar harus!


1
Terimakasih atas infonya.
Jasper Blues

13

Menurut referensi bahasa, tidak ada persyaratan untuk kelas untuk membuat subkelas kelas akar standar apa pun, sehingga Anda dapat menyertakan atau menghilangkan kelas super sesuai kebutuhan.

Perhatikan bahwa menghilangkan superclass dari deklarasi kelas, tidak menetapkan superclass dasar implisit dalam bentuk apa pun. Ini mendefinisikan kelas dasar, yang secara efektif akan menjadi akar untuk hierarki kelas independen.

Dari referensi bahasa:

Kelas Swift tidak mewarisi dari kelas dasar universal. Kelas yang Anda tentukan tanpa menentukan superclass otomatis menjadi kelas dasar untuk Anda bangun.

Mencoba mereferensikan superdari kelas tanpa kelas super (yaitu kelas dasar) akan menghasilkan kesalahan waktu kompilasi

'super' members cannot be referenced in a root class

1
Ya. Jika Anda mencoba membuat file sumber Cocoa or Cocoa Touch dalam konteks proyek, formulir tempat Anda menyisipkan subkelas sebenarnya mencegah Anda membuat kelas sambil membiarkannya kosong. Anda dapat menghapus superclass nanti setelah dibuat.
Cezar

1
Terima kasih. Menggunakan pengiriman statis dan vtable masuk akal untuk pemrograman sistem atau penyetelan kinerja. Untuk konsistensi dengan Kakao asli, menurut saya dinamika harus menjadi default. (Kecuali jika seseorang dapat meyakinkan saya sebaliknya, maka pertanyaan ini).
Jasper Blues

1

Saya yakin bahwa sebagian besar data Swift tidak akan tersedia objc. Hanya bagian-bagian yang perlu berkomunikasi dengan infrastruktur Objective C yang akan secara eksplisit ditandai.

Sejauh mana introspeksi runtime akan ditambahkan ke bahasa, saya tidak tahu. Intersepsi metode kemungkinan akan menjadi hanya mungkin jika metode secara eksplisit mengizinkannya. Ini adalah tebakan saya, tetapi hanya desainer bahasa di dalam Apple yang benar-benar tahu kemana tujuan mereka sebenarnya.


Bagi saya, masuk akal menjadikan dinamisme sebagai default (melalui perluasan NSObject, menggunakan dekorasi '@objc' atau pendekatan lain). Tampaknya ketika tidak ada kelas dasar, Swift akan menyukai pengiriman statis / vtable, yang berkinerja lebih baik, tetapi dalam kebanyakan kasus ini tidak diperlukan. . (90% keuntungan datang dari penyetelan 10% kode). Harapan saya adalah bahwa konsistensi dengan dinamisme Objective-C adalah opt-out daripada opt-in.
Jasper Blues

Cara bahasa dirancang, ini adalah pilihan opsional. Sejauh yang kami ketahui, sangat mungkin bahwa di masa mendatang, API sistem akan ditambahkan yang tidak secara asli bersifat keberatan. Dalam jangka menengah / panjang mereka bahkan dapat memigrasikan pustaka yang ada ke kode non-objc dengan lapisan kompatibilitas tipis di objc yang memanggil kode non-obyektif. Kami hanya tidak tahu. Kami mungkin akan bisa membuatnya educated guessesdalam beberapa tahun dari sekarang. Tapi untuk saat ini itu hanya tanda tanya besar.
File Analog

@JasperBlues Saya berpendapat bahwa dinamisme tidak diperlukan sebagian besar waktu dan saya lebih suka memiliki kinerja secara default dan kemudian memilih perilaku dinamis yang diperlukan. Untuk masing-masing miliknya sendiri, saya kira :)
Lance

@Lance H. Mungkin. Saya masih prihatin tentang: pengamat, AOP, kerangka kerja uji coba, kerangka kerja analitik, dll. dan hal tentang kinerja adalah bahwa 90% keuntungan datang dari penyetelan 10%. . jadi itulah alasan saya - ikut serta untuk 10% kasus tersebut. Saya pikir AOP akan menjadi masalah besar untuk aplikasi perusahaan iOS, tetapi itu bisa dilakukan dengan menggunakan alat kompiler seperti di C ++. . pastinya game, komputasi ilmiah, grafik, dll, pengembang akan menyambut performa yang lebih baik :)
Jasper Blues

1

Kalimat berikut ini disalin dari Swift-eBook Apple dan memberikan jawaban yang sesuai untuk pertanyaan Anda:

Mendefinisikan Kelas-Basis

Setiap kelas yang tidak mewarisi dari kelas lain dikenal sebagai kelas dasar.

Kelas Swift tidak mewarisi dari kelas dasar universal. Kelas yang Anda tentukan tanpa menentukan superclass otomatis menjadi kelas dasar untuk Anda bangun.


Referensi

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_251


-6

Itu normal. Lihatlah tujuan desain Swift: Tujuannya adalah untuk menghilangkan kelas besar masalah pemrograman. Metode swizzling mungkin bukan salah satu hal yang ingin Anda lakukan dengan Swift.


3
Metode swizzling adalah cara untuk mencapai pola intersep saat runtime. Salah satu kegunaannya adalah untuk menerapkan masalah lintas sektor sesuai dengan prinsip Pemrograman Berorientasi Aspek. Pemberitahuan Apple sendiri, pengamat properti (built-in untuk swift), data inti semua menggunakan swizzling untuk efek yang baik. . Salah satu hal yang membuat orang terpikat pada Objective-C meskipun sintaksnya kikuk adalah dinamisme ini, yang membuatnya mudah untuk memberikan solusi elegan kapan pun pola intersep diperlukan. . sebenarnya tidak ada kerangka kerja AOP formal untuk Objc, karena bahan bakunya sangat bagus.
Jasper Blues

Fakta bahwa begitulah cara melakukannya sekarang tidak berarti bahwa hal itu akan dilakukan besok. Seperti yang Anda katakan, pemberitahuan, pengamat properti, delegasi, dan sejenisnya telah atau mungkin disediakan secara native. Bahasanya akan berkembang, dan kita tidak tahu ke arah mana. Ini telah memperoleh banyak hal dalam hal dukungan untuk pemrograman fungsional. Tapi itu melakukannya dengan cara yang tidak biasa, jadi saya tidak tahu berapa banyak yang hilang. Namun sejauh yang kami tahu, mereka mungkin mengarah ke mutasi yang mencegah dan mendorong pemrograman fungsional murni. Bagaimana jika masa depan UI reaktif? Belum ada cara untuk mengetahuinya.
File Analog

1
Ya, tetapi semua hal ini bergantung pada intersepsi, yang dapat dilakukan dengan dua cara: waktu kompilasi (C ++) atau runtime (Ruby, Objective-C, Java (melalui asm, cglib, ApsectJ, dll)). Bahasa modern cenderung melakukannya saat runtime. Orang-orang menyukai Objective-C, karena ia berperilaku seperti bahasa modern meskipun sudah tua. Seperti yang Anda katakan, semakin banyak yang dimasukkan ke dalam bahasa, semakin baik (asalkan dilakukan dengan baik!). . tetapi untuk saat ini kita dapat memanfaatkan warisan yang disediakan oleh Objc / Foundation, itulah sebabnya saya berharap memperluas NSObject menjadi praktik standar untuk aplikasi sehari-hari selama beberapa tahun ke depan.
Jasper Blues
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.