Objective-C tidak memiliki ruang nama; itu seperti C, semuanya dalam satu namespace global. Praktik umum adalah untuk mengawali kelas dengan inisial, misalnya jika Anda bekerja di IBM, Anda bisa mengawali mereka dengan "IBM"; jika Anda bekerja untuk Microsoft, Anda dapat menggunakan "MS"; dan seterusnya. Terkadang inisial merujuk pada proyek, misalnya kelas awalan Adium dengan "AI" (karena tidak ada perusahaan di belakangnya sehingga Anda dapat mengambil inisial). Awalan Apple kelas dengan NS dan mengatakan awalan ini dicadangkan untuk Apple saja.
Sejauh ini sangat baik. Tetapi menambahkan 2 hingga 4 huruf ke nama kelas di depan adalah namespace yang sangat, sangat terbatas. Misalnya MS atau AI dapat memiliki arti yang sama sekali berbeda (AI bisa jadi Kecerdasan Buatan misalnya) dan beberapa pengembang lain mungkin memutuskan untuk menggunakannya dan membuat kelas yang sama namanya. Bang , tabrakan namespace.
Oke, jika ini adalah tabrakan antara salah satu kelas Anda dan salah satu kerangka eksternal yang Anda gunakan, Anda dapat dengan mudah mengubah penamaan kelas Anda, bukan masalah besar. Tetapi bagaimana jika Anda menggunakan dua kerangka kerja eksternal, kedua kerangka kerja yang Anda tidak memiliki sumbernya dan Anda tidak dapat mengubahnya? Aplikasi Anda terhubung dengan keduanya dan Anda mendapat konflik nama. Bagaimana Anda menyelesaikannya? Apa cara terbaik untuk mengatasi mereka sedemikian rupa sehingga Anda masih dapat menggunakan kedua kelas?
Di C Anda dapat mengatasi ini dengan tidak menautkan langsung ke perpustakaan, sebaliknya Anda memuat perpustakaan saat runtime, menggunakan dlopen (), kemudian menemukan simbol yang Anda cari menggunakan dlsym () dan menetapkannya ke simbol global (bahwa Anda dapat memberi nama dengan cara apa pun yang Anda suka) dan kemudian mengaksesnya melalui simbol global ini. Misalnya jika Anda memiliki konflik karena beberapa pustaka C memiliki fungsi bernama open (), Anda bisa mendefinisikan variabel bernama myOpen dan mengarahkannya ke fungsi open () pustaka, jadi ketika Anda ingin menggunakan sistem open () , Anda hanya menggunakan open () dan ketika Anda ingin menggunakan yang lain, Anda mengaksesnya melalui pengenal myOpen.
Apakah sesuatu yang serupa mungkin terjadi di Objective-C dan jika tidak, apakah ada solusi cerdas dan rumit lainnya yang dapat Anda gunakan menyelesaikan konflik namespace? Ada ide?
Memperbarui:
Untuk memperjelas ini: jawaban yang menyarankan cara menghindari tabrakan namespace di muka atau cara membuat namespace yang lebih baik tentu disambut; namun, saya tidak akan menerimanya sebagai jawaban karena mereka tidak menyelesaikan masalah saya. Saya memiliki dua perpustakaan dan nama kelas mereka bertabrakan. Saya tidak bisa mengubahnya; Saya tidak punya sumber keduanya. Tabrakan sudah ada dan tips tentang bagaimana hal itu bisa dihindari sebelumnya tidak akan membantu lagi. Saya dapat meneruskannya ke pengembang kerangka kerja ini dan berharap mereka memilih namespace yang lebih baik di masa depan, tetapi untuk saat ini saya sedang mencari solusi untuk bekerja dengan kerangka kerja sekarang dalam satu aplikasi. Ada solusi untuk membuat ini mungkin?
sumber
Jawaban:
Jika Anda tidak perlu menggunakan kelas dari kedua kerangka kerja secara bersamaan, dan Anda menargetkan platform yang mendukung NSBundle unloading (OS X 10.4 atau lebih baru, tidak ada dukungan GNUStep), dan kinerja benar-benar bukan masalah bagi Anda, saya percaya bahwa Anda bisa memuat satu kerangka kerja setiap kali Anda perlu menggunakan kelas dari itu, dan kemudian membongkar dan memuat yang lain ketika Anda perlu menggunakan kerangka lainnya.
Ide awal saya adalah menggunakan NSBundle untuk memuat salah satu framework, lalu menyalin atau mengganti nama kelas-kelas di dalam framework itu, dan kemudian memuat framework lainnya. Ada dua masalah dengan ini. Pertama, saya tidak bisa menemukan fungsi untuk menyalin data yang diarahkan untuk mengubah nama atau menyalin kelas, dan kelas lain mana pun dalam kerangka kerja pertama yang merujuk kelas yang diubah namanya sekarang akan merujuk kelas dari kerangka kerja lain.
Anda tidak perlu menyalin atau mengganti nama kelas jika ada cara untuk menyalin data yang ditunjukkan oleh IMP. Anda bisa membuat kelas baru dan kemudian menyalin lebih dari ivar, metode, properti, dan kategori. Jauh lebih banyak pekerjaan, tetapi itu mungkin. Namun, Anda masih akan memiliki masalah dengan kelas-kelas lain dalam kerangka kerja yang merujuk kelas yang salah.
EDIT: Perbedaan mendasar antara runtime C dan Objective-C adalah, seperti yang saya pahami, ketika pustaka dimuat, fungsi-fungsi di pustaka berisi pointer ke simbol apa pun yang mereka referensi, sedangkan di Objective-C, mereka berisi representasi string dari nama simbolnya. Jadi, dalam contoh Anda, Anda dapat menggunakan dlsym untuk mendapatkan alamat simbol dalam memori dan melampirkannya ke simbol lain. Kode lain di perpustakaan masih berfungsi karena Anda tidak mengubah alamat simbol asli. Objective-C menggunakan tabel pencarian untuk memetakan nama kelas ke alamat, dan ini merupakan pemetaan 1-1, sehingga Anda tidak dapat memiliki dua kelas dengan nama yang sama. Jadi, untuk memuat kedua kelas, salah satu dari mereka harus memiliki nama yang diubah. Namun, ketika kelas lain perlu mengakses salah satu kelas dengan nama itu,
sumber
Awalan kelas Anda dengan awalan unik pada dasarnya adalah satu-satunya pilihan tetapi ada beberapa cara untuk membuat ini kurang memberatkan dan jelek. Ada diskusi panjang opsi di sini . Favorit saya adalah
@compatibility_alias
direktif kompilasi Objective-C (dijelaskan di sini ). Anda dapat menggunakan@compatibility_alias
untuk "mengubah nama" kelas, memungkinkan Anda untuk memberi nama kelas Anda menggunakan FQDN atau awalan semacam itu:Sebagai bagian dari strategi lengkap, Anda bisa mengawali semua kelas Anda dengan awalan unik seperti FQDN dan kemudian membuat header dengan semua
@compatibility_alias
(Saya akan membayangkan Anda bisa secara otomatis menghasilkan kata header).Kelemahan dari awalan seperti ini adalah bahwa Anda harus memasukkan nama kelas yang benar (misalnya di
COM_WHATEVER_ClassName
atas) dalam apa pun yang membutuhkan nama kelas dari string selain kompiler. Khususnya,@compatibility_alias
adalah arahan kompiler, bukan fungsi runtime sehinggaNSClassFromString(ClassName)
akan gagal (kembalinil
) - Anda harus menggunakanNSClassFromString(COM_WHATERVER_ClassName)
. Anda dapat menggunakanibtool
fase build untuk memodifikasi nama kelas di Interface Builder nib / xib sehingga Anda tidak perlu menulis COM_WHATEVER _... lengkap di Interface Builder.Peringatan terakhir: karena ini adalah kompiler directive (dan yang tidak jelas pada saat itu), itu mungkin tidak portabel di kompiler. Secara khusus, saya tidak tahu apakah itu bekerja dengan frontend dentang dari proyek LLVM, meskipun itu harus bekerja dengan LLVM-GCC (LLVM menggunakan frontend GCC).
sumber
Beberapa orang telah membagikan beberapa kode rumit dan pintar yang mungkin membantu menyelesaikan masalah. Beberapa saran mungkin berhasil, tetapi semuanya kurang dari ideal, dan beberapa di antaranya benar-benar tidak menyenangkan untuk diterapkan. (Kadang-kadang peretasan yang jelek tidak bisa dihindari, tetapi saya mencoba menghindarinya kapan pun saya bisa.) Dari sudut pandang praktis, berikut adalah saran saya.
Saya menduga bahwa biaya lisensi, ketentuan, dan jangka waktu dapat mencegah tindakan instan pada salah satu poin ini. Semoga Anda dapat menyelesaikan konflik secepat mungkin. Semoga berhasil!
sumber
Ini kotor, tetapi Anda bisa menggunakan objek terdistribusi untuk mempertahankan salah satu kelas hanya di alamat program bawahan dan RPC untuk itu. Itu akan menjadi berantakan jika Anda melewati banyak hal bolak-balik (dan mungkin tidak mungkin jika kedua kelas secara langsung memanipulasi tampilan, dll).
Ada solusi potensial lainnya, tetapi banyak dari mereka bergantung pada situasi yang tepat. Secara khusus, apakah Anda menggunakan runtime modern atau lama, apakah Anda gemuk atau arsitektur tunggal, 32 atau 64 bit, rilis OS apa yang Anda targetkan, apakah Anda menghubungkan secara dinamis, menghubungkan secara statis, atau apakah Anda punya pilihan, dan apakah berpotensi boleh melakukan sesuatu yang mungkin memerlukan pemeliharaan untuk pembaruan perangkat lunak baru.
Jika Anda benar-benar putus asa, yang bisa Anda lakukan adalah:
Hal di atas akan menjadi sangat padat karya, dan jika Anda perlu mengimplementasikannya pada banyak lengkungan dan versi runtime yang berbeda itu akan sangat tidak menyenangkan, tetapi pasti dapat dibuat untuk bekerja.
sumber
Sudahkah Anda mempertimbangkan untuk menggunakan fungsi runtime (/usr/include/objc/runtime.h) untuk mengkloning salah satu kelas yang bertentangan ke kelas yang tidak bertabrakan, dan kemudian memuat kerangka kerja kelas bertabrakan? (Ini akan membutuhkan kerangka kerja bertabrakan yang dimuat pada waktu yang berbeda untuk bekerja.)
Anda dapat memeriksa kelas ivars, metode (dengan nama dan alamat implementasi) dan nama dengan runtime, dan membuat Anda sendiri secara dinamis untuk memiliki tata letak ivar yang sama, nama metode / alamat implementasi, dan hanya berbeda dengan nama (untuk menghindari tabrakan)
sumber
Situasi putus asa membutuhkan tindakan putus asa. Sudahkah Anda mempertimbangkan meretas kode objek (atau file perpustakaan) dari salah satu perpustakaan, mengubah simbol bertabrakan menjadi nama alternatif - dengan panjang yang sama tetapi dengan ejaan yang berbeda (tetapi, rekomendasi, panjang nama yang sama)? Sangat jahat.
Tidak jelas apakah kode Anda secara langsung memanggil dua fungsi dengan nama yang sama tetapi implementasi yang berbeda atau apakah konflik tidak langsung (juga tidak jelas apakah itu membuat perbedaan). Namun, setidaknya ada peluang di luar bahwa penggantian nama akan berhasil. Mungkin juga merupakan ide, untuk meminimalkan perbedaan dalam ejaan, sehingga jika simbol berada dalam urutan diurutkan dalam sebuah tabel, penamaan ulang tidak memindahkan hal-hal yang rusak. Hal-hal seperti pencarian biner menjadi kesal jika array yang mereka cari tidak dalam urutan seperti yang diharapkan.
sumber
@compatibility_alias
akan dapat menyelesaikan konflik namespace kelas, misNamun, ini tidak akan menyelesaikan salah satu enums, typedef, atau collision namespace protokol . Selain itu, itu tidak bermain dengan baik dengan
@class
decl maju dari kelas asli. Karena sebagian besar kerangka kerja akan datang dengan hal-hal non-kelas ini seperti typedefs, Anda mungkin tidak akan dapat memperbaiki masalah namespace dengan hanya kompatibilitas_alias.Saya melihat masalah yang sama dengan Anda , tetapi saya memiliki akses ke sumber dan sedang membangun kerangka kerja. Solusi terbaik yang saya temukan untuk ini adalah menggunakan
@compatibility_alias
kondisional dengan #defines untuk mendukung enum / typedefs / protokol / dll. Anda dapat melakukan ini secara kondisional pada unit kompilasi untuk header yang dimaksud untuk meminimalkan risiko memperluas barang-barang di kerangka bertabrakan lainnya.sumber
Tampaknya masalahnya adalah Anda tidak dapat mereferensikan file header dari kedua sistem dalam unit terjemahan yang sama (file sumber). Jika Anda membuat pembungkus objektif-c di sekitar pustaka (menjadikannya lebih bermanfaat dalam proses), dan hanya menyertakan header untuk setiap pustaka dalam implementasi kelas pembungkus, yang secara efektif akan memisahkan tabrakan nama.
Saya tidak punya cukup pengalaman dengan ini dalam tujuan-c (baru memulai), tetapi saya percaya itulah yang akan saya lakukan di C.
sumber
Membuat awalan file adalah solusi paling sederhana yang saya ketahui. Cocoadev memiliki halaman namespace yang merupakan upaya komunitas untuk menghindari tabrakan namespace. Jangan ragu untuk menambahkan milik Anda sendiri ke daftar ini, saya percaya itulah gunanya.
http://www.cocoadev.com/index.pl?CreoseYourOwnPrefix Anda
sumber
Jika Anda memiliki tabrakan, saya sarankan Anda berpikir keras tentang bagaimana Anda dapat memperbaiki salah satu kerangka kerja dari aplikasi Anda. Memiliki tabrakan menunjukkan bahwa keduanya melakukan hal yang sama, dan Anda mungkin bisa menggunakan kerangka tambahan hanya dengan refactoring aplikasi Anda. Ini tidak hanya akan memecahkan masalah namespace Anda, tetapi juga akan membuat kode Anda lebih kuat, lebih mudah dirawat, dan lebih efisien.
Lebih dari solusi yang lebih teknis, jika saya berada di posisi Anda ini akan menjadi pilihan saya.
sumber
Jika tabrakan hanya pada level tautan statis maka Anda dapat memilih perpustakaan mana yang digunakan untuk menyelesaikan simbol:
Jika
foo.o
danbar.o
kedua referensi simbolrat
makalibdog
akan menyelesaikanfoo.o
'srat
danlibcat
akan menyelesaikanbar.o
' srat
.sumber
Hanya sebuah pemikiran .. tidak diuji atau terbukti dan bisa menjadi tanda tetapi dalam apakah Anda mempertimbangkan untuk menulis adaptor untuk kelas yang Anda gunakan dari kerangka kerja yang lebih sederhana .. atau setidaknya antarmuka mereka?
Jika Anda menulis pembungkus di sekitar kerangka kerja yang lebih sederhana (atau yang paling sedikit antarmuka Anda aksesnya) tidak akan mungkin untuk mengkompilasi pembungkus itu ke perpustakaan. Mengingat perpustakaan dikompilasi dan hanya header -nya yang perlu didistribusikan, Anda akan secara efektif menyembunyikan kerangka kerja yang mendasarinya dan akan bebas untuk menggabungkannya dengan kerangka kerja kedua dengan bentrok.
Saya menghargai tentu saja bahwa ada saat-saat ketika Anda perlu menggunakan kelas dari kedua kerangka kerja pada saat yang sama, namun, Anda dapat menyediakan pabrik untuk adaptor kelas lebih lanjut dari kerangka kerja itu. Di belakang titik itu saya kira Anda akan perlu sedikit refactoring untuk mengekstrak antarmuka yang Anda gunakan dari kedua kerangka kerja yang seharusnya memberikan titik awal yang baik bagi Anda untuk membangun pembungkus Anda.
Anda dapat membangun di atas pustaka saat Anda dan saat Anda membutuhkan fungsionalitas lebih lanjut dari pustaka terbungkus, dan cukup kompilasi ulang saat Anda mengubahnya.
Sekali lagi, sama sekali tidak terbukti tetapi rasanya ingin menambahkan perspektif. semoga membantu :)
sumber
Jika Anda memiliki dua kerangka kerja yang memiliki nama fungsi yang sama, Anda bisa mencoba memuat kerangka kerja secara dinamis. Itu akan tidak berlaku, tetapi mungkin. Bagaimana melakukannya dengan kelas Objective-C, saya tidak tahu. Saya menduga
NSBundle
kelas akan memiliki metode yang akan memuat kelas tertentu.sumber