Menurut pemahaman saya, orang harus menggunakan deklarasi kelas-maju jika ClassA perlu menyertakan header ClassB, dan ClassB perlu menyertakan header ClassA untuk menghindari inklusi melingkar. Saya juga mengerti bahwa an #import
itu sederhanaifndef
sehingga suatu penyertaan hanya terjadi sekali.
Pertanyaan saya adalah ini: Kapan seseorang menggunakan #import
dan kapan menggunakannya @class
? Terkadang jika saya menggunakan @class
deklarasi, saya melihat peringatan kompiler umum seperti berikut ini:
warning: receiver 'FooController' is a forward class and corresponding @interface may not exist.
Akan sangat senang untuk memahami ini, dibandingkan hanya menghapus @class
deklarasi maju dan melemparkan #import
ke dalam untuk membungkam peringatan yang diberikan kompiler kepada saya.
sumber
Jawaban:
Jika Anda melihat peringatan ini:
Anda perlu ke
#import
file, tetapi Anda bisa melakukannya di file implementasi Anda (.m), dan gunakan@class
deklarasi di file header Anda.@class
tidak (biasanya) menghapus kebutuhan untuk#import
file, itu hanya memindahkan persyaratan lebih dekat ke tempat informasi berguna.Sebagai contoh
Jika Anda mengatakan
@class MyCoolClass
, kompiler tahu bahwa ia mungkin melihat sesuatu seperti:Tidak perlu khawatir tentang apa pun selain
MyCoolClass
kelas yang valid, dan itu harus menyediakan ruang untuk pointer ke sana (sungguh, hanya pointer). Jadi, di tajuk Anda,@class
cukup 90% dari waktu.Namun, jika Anda perlu membuat atau mengakses
myObject
anggota, Anda harus memberi tahu kompilator apa metode tersebut. Pada titik ini (mungkin dalam file implementasi Anda), Anda harus#import "MyCoolClass.h"
, untuk memberi tahu kompiler informasi tambahan lebih dari sekadar "ini kelas".sumber
@class
sesuatu dalam Anda.h
file, namun lupa untuk#import
di m, cobalah untuk mengakses metode pada@class
objek ed, dan mendapatkan peringatan seperti:warning: no -X method found
.Tiga aturan sederhana:
#import
kelas super, dan protokol yang diadopsi, dalam file header (.h
file).#import
semua kelas, dan protokol, Anda mengirim pesan ke dalam implementasi (.m
file).Jika Anda meneruskan pernyataan dalam file implementasi, maka Anda mungkin melakukan sesuatu yang salah.
sumber
Lihatlah dokumentasi Bahasa Pemrograman Objective-C pada ADC
Di bawah bagian tentang Mendefinisikan Kelas | Class Interface menjelaskan mengapa ini dilakukan:
Saya harap ini membantu.
sumber
Gunakan deklarasi maju dalam file header jika perlu, dan
#import
file header untuk setiap kelas yang Anda gunakan dalam implementasi. Dengan kata lain, Anda selalu#import
file yang Anda gunakan dalam implementasi Anda, dan jika Anda perlu referensi kelas di file header Anda menggunakan deklarasi maju juga.The pengecualian untuk ini adalah bahwa Anda harus
#import
kelas atau protokol resmi Anda mewarisi dari dalam file header (dalam hal ini Anda tidak perlu impor dalam pelaksanaannya).sumber
Praktik yang umum adalah menggunakan @class dalam file header (tetapi Anda masih perlu #mengimpor superclass), dan #memasukkan dalam file implementasi. Ini akan menghindari inklusi melingkar, dan itu hanya berfungsi.
sumber
#import
"seperti arahan C #include, kecuali bahwa itu memastikan bahwa file yang sama tidak pernah dimasukkan lebih dari sekali." Jadi menurut ini#import
mengurus inklusi melingkar,@class
arahan tidak terlalu membantu dengan itu.Keuntungan lain: kompilasi cepat
Jika Anda menyertakan file header, setiap perubahan di dalamnya menyebabkan file saat ini juga untuk dikompilasi tetapi ini tidak terjadi jika nama kelas dimasukkan sebagai
@class name
. Tentu saja Anda harus menyertakan header di file sumbersumber
Jawaban sederhana: Anda
#import
atau#include
ketika ada ketergantungan fisik. Jika tidak, Anda menggunakan deklarasi maju (@class MONClass
,struct MONStruct
,@protocol MONProtocol
).Berikut adalah beberapa contoh umum ketergantungan fisik:
CGPoint
sebagai ivar atau properti, kompiler perlu melihat deklarasiCGPoint
.Compiler sebenarnya sangat toleran dalam hal ini. Ini akan meninggalkan petunjuk (seperti yang di atas), tetapi Anda dapat dengan mudah membuang tumpukan Anda jika Anda mengabaikannya dan tidak melakukannya
#import
dengan benar. Meskipun harus (IMO), kompiler tidak menjalankan ini. Di ARC, kompiler lebih ketat karena bertanggung jawab untuk penghitungan referensi. Apa yang terjadi adalah kompiler kembali ke default ketika menemukan metode yang tidak dikenal yang Anda panggil. Setiap nilai dan parameter pengembalian diasumsikanid
. Dengan demikian, Anda harus menghapus setiap peringatan dari basis kode Anda karena ini harus dianggap sebagai ketergantungan fisik. Ini analog dengan memanggil fungsi C yang tidak dideklarasikan. Dengan C, parameter diasumsikanint
.Alasan Anda lebih suka deklarasi maju adalah bahwa Anda dapat mengurangi waktu pembuatan Anda dengan faktor karena ada ketergantungan minimal. Dengan deklarasi maju, kompiler melihat ada nama, dan dapat dengan benar mem-parsing dan mengkompilasi program tanpa melihat deklarasi kelas atau semua dependensinya ketika tidak ada ketergantungan fisik. Bangunan bersih membutuhkan waktu lebih sedikit. Bangunan tambahan membutuhkan waktu lebih sedikit. Tentu, Anda akan menghabiskan lebih banyak waktu untuk memastikan bahwa semua tajuk yang Anda butuhkan dapat dilihat oleh setiap terjemahan sebagai konsekuensinya, tetapi ini terbayar dengan waktu pembuatan yang berkurang dengan cepat (dengan asumsi proyek Anda tidak kecil).
Jika Anda menggunakan
#import
atau#include
sebagai gantinya, Anda membuat lebih banyak pekerjaan di kompiler daripada yang diperlukan. Anda juga memperkenalkan dependensi tajuk yang rumit. Anda bisa menyamakan ini dengan algoritma brute-force. Kapan kamu#import
, Anda menyeret banyak informasi yang tidak perlu, yang membutuhkan banyak memori, disk I / O, dan CPU untuk mengurai dan mengkompilasi sumber.ObjC cukup dekat dengan ideal untuk bahasa berbasis C berkaitan dengan ketergantungan karena
NSObject
tipe tidak pernah bernilai -NSObject
jenis selalu referensi pointer dihitung. Jadi Anda bisa lolos dengan waktu kompilasi yang sangat cepat jika Anda menyusun dependensi program Anda dengan tepat dan meneruskan jika memungkinkan karena ada sangat sedikit ketergantungan fisik yang diperlukan. Anda juga dapat mendeklarasikan properti di ekstensi kelas untuk meminimalkan ketergantungan. Itu bonus besar untuk sistem besar - Anda akan tahu perbedaannya jika Anda pernah mengembangkan basis kode C ++ besar.Oleh karena itu, rekomendasi saya adalah menggunakan ke depan jika memungkinkan, dan kemudian ke
#import
mana ada ketergantungan fisik. Jika Anda melihat peringatan atau yang menyiratkan ketergantungan fisik - perbaiki semuanya. Cara mengatasinya#import
dalam file implementasi Anda.Saat Anda membangun pustaka, Anda kemungkinan akan mengklasifikasikan beberapa antarmuka sebagai grup, dalam hal ini Anda akan
#import
pustaka di mana ketergantungan fisik diperkenalkan (misalnya#import <AppKit/AppKit.h>
). Ini dapat memperkenalkan ketergantungan, tetapi pengelola perpustakaan sering kali dapat menangani dependensi fisik untuk Anda sesuai kebutuhan - jika mereka memperkenalkan fitur, mereka dapat meminimalkan dampak yang ditimbulkannya pada bangunan Anda.sumber
NSObject types are never values -- NSObject types are always reference counted pointers.
tidak sepenuhnya benar. Blok melempar celah dalam jawaban Anda, hanya mengatakan.Saya melihat banyak "Lakukan dengan cara ini" tetapi saya tidak melihat jawaban untuk "Mengapa?"
Jadi: Mengapa Anda harus @class di header Anda dan #import hanya dalam implementasi Anda? Anda menggandakan pekerjaan Anda dengan harus @class dan #import sepanjang waktu. Kecuali Anda menggunakan warisan. Dalam hal ini Anda akan #mengimpor beberapa kali untuk satu kelas @. Maka Anda harus ingat untuk menghapus dari banyak file yang berbeda jika tiba-tiba Anda memutuskan tidak perlu lagi mengakses deklarasi.
Mengimpor file yang sama beberapa kali bukan masalah karena sifat #import. Kompilasi kinerja juga bukan masalah. Jika ya, kami tidak akan mengimpor # Cocoa / Cocoa.h atau sejenisnya di hampir semua file header yang kita miliki.
sumber
jika kita melakukan ini
berarti kita mewarisi Class_A ke dalam Class_B, di Class_B kita dapat mengakses semua variabel class_A.
jika kita melakukan ini
di sini kita mengatakan bahwa kita menggunakan Class_A dalam program kita, tetapi jika kita ingin menggunakan variabel Class_A di Class_B kita harus #memasukkan Class_A dalam file .m (buat objek dan gunakan fungsi dan variabelnya).
sumber
untuk info tambahan tentang dependensi file & # impor & @ kelas periksa ini:
http://qualitycoding.org/file-dependencies/ itu adalah artikel yang bagus
ringkasan artikel
sumber
Ketika saya berkembang, saya hanya memiliki tiga hal dalam pikiran yang tidak pernah menyebabkan masalah bagi saya.
Untuk semua kelas lain (subclass dan kelas anak di proyek saya sendiri), saya mendeklarasikannya melalui kelas maju.
sumber
Jika Anda mencoba mendeklarasikan variabel, atau properti di file header Anda, yang belum Anda impor, Anda akan mendapatkan kesalahan dengan mengatakan bahwa kompiler tidak mengetahui kelas ini.
Pikiran pertama Anda mungkin
#import
itu.Ini dapat menyebabkan masalah dalam beberapa kasus.
Misalnya jika Anda menerapkan banyak metode-C di file header, atau struct, atau yang serupa, karena itu tidak boleh diimpor beberapa kali.
Karena itu Anda dapat memberi tahu kompiler dengan
@class
:Itu pada dasarnya memberitahu kompiler untuk tutup mulut dan kompilasi, meskipun tidak yakin apakah kelas ini akan diimplementasikan.
Anda biasanya akan menggunakan
#import
dalam m dan@class
di H file.sumber
Teruskan deklarasi hanya untuk mencegah compiler menampilkan kesalahan.
kompiler akan tahu bahwa ada kelas dengan nama yang telah Anda gunakan dalam file header Anda untuk menyatakan.
sumber
Compiler akan mengeluh hanya jika Anda akan menggunakan kelas itu sedemikian rupa sehingga kompiler perlu mengetahui implementasinya.
Ex:
Itu tidak akan mengeluh jika Anda hanya akan menggunakannya sebagai pointer. Tentu saja, Anda harus #memindahkannya ke file implementasi (jika Anda membuat instance objek dari kelas itu) karena ia perlu mengetahui konten kelas untuk membuat instance objek.
CATATAN: #import tidak sama dengan #include. Ini berarti tidak ada yang disebut impor melingkar. import adalah jenis permintaan bagi kompiler untuk melihat file tertentu untuk beberapa informasi. Jika informasi itu sudah tersedia, kompiler mengabaikannya.
Coba saja ini, impor Ah di Bh dan Bh di Ah Tidak akan ada masalah atau keluhan dan itu akan berfungsi dengan baik juga.
Kapan menggunakan @class
Anda menggunakan @class hanya jika Anda bahkan tidak ingin mengimpor header di header Anda. Ini bisa menjadi kasus di mana Anda bahkan tidak peduli untuk tahu apa kelas itu nantinya. Kasus di mana Anda bahkan mungkin belum memiliki header untuk kelas itu.
Contohnya adalah Anda menulis dua pustaka. Satu kelas, sebut saja A, ada di satu perpustakaan. Pustaka ini menyertakan tajuk dari pustaka kedua. Header itu mungkin memiliki pointer A tetapi sekali lagi mungkin tidak perlu menggunakannya. Jika perpustakaan 1 belum tersedia, perpustakaan B tidak akan diblokir jika Anda menggunakan @class. Tetapi jika Anda ingin mengimpor Ah, maka kemajuan perpustakaan 2 diblokir.
sumber
Pikirkan @class dengan mengatakan pada kompiler "percayalah, ini ada".
Pikirkan #import sebagai salin-rekat.
Anda ingin meminimalkan jumlah impor yang Anda miliki karena sejumlah alasan. Tanpa penelitian, hal pertama yang terlintas dalam pikiran adalah mengurangi waktu kompilasi.
Perhatikan bahwa ketika Anda mewarisi dari kelas, Anda tidak bisa hanya menggunakan deklarasi maju. Anda perlu mengimpor file, sehingga kelas yang Anda deklarasikan tahu bagaimana itu didefinisikan.
sumber
Ini adalah contoh skenario, di mana kita membutuhkan @class.
Pertimbangkan jika Anda ingin membuat protokol di dalam file header, yang memiliki parameter dengan tipe data dari kelas yang sama, maka Anda dapat menggunakan @class. Harap ingat bahwa Anda juga dapat mendeklarasikan protokol secara terpisah, ini hanyalah sebuah contoh.
sumber