Apa perbedaan antara #import dan #include di Objective-C?

385

Apa perbedaan antara #import dan #include dalam Objective-C dan adakah saat-saat di mana Anda harus menggunakannya? Apakah satu sudah usang?

Saya membaca tutorial berikut: http://www.otierney.net/objective-c.html#preamble dan paragrafnya tentang #import dan #include tampaknya bertentangan sendiri atau setidaknya tidak jelas.

Ryan Guill
sumber

Jawaban:

340

Arahan #import ditambahkan ke Objective-C sebagai versi perbaikan dari #include. Namun apakah itu diperbaiki atau tidak, masih menjadi bahan perdebatan. #import memastikan bahwa file hanya pernah dimasukkan sekali sehingga Anda tidak pernah memiliki masalah dengan menyertakan rekursif. Namun, sebagian besar file header yang layak melindungi diri terhadap hal ini, jadi itu tidak terlalu banyak manfaatnya.

Pada dasarnya, terserah Anda untuk memutuskan mana yang ingin Anda gunakan. Saya cenderung #memindahkan header untuk hal-hal Objective-C (seperti definisi kelas dan semacamnya) dan #mengikutkan hal-hal standar C yang saya butuhkan. Sebagai contoh, salah satu file sumber saya mungkin terlihat seperti ini:

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>
Jason Coco
sumber
65
Bahkan jika file header berisi menyertakan penjaga, masih ada hit kinerja selama kompilasi jika Anda menggunakan #include - kompiler harus membuka setiap file header untuk melihat menyertakan penjaga.
Matt Dillard
4
pelindung tajuk adalah arahan preprosesor yang memastikan tajuk hanya disertakan satu kali dalam file sumber.
Jason Coco
8
Saya pikir #import sebenarnya adalah tambahan oleh GCC, bukan oleh Objective-C. Anda dapat menggunakannya dalam bahasa non-ObjC selama Anda mengkompilasi dengan GCC (atau Dentang)
Dave DeLong
34
@dave - #import adalah tambahan Objective-C ke preprocessor. GCC hanya mendukungnya dalam file sumber C dan C ++ juga, meskipun mereka secara resmi menyarankan untuk tidak menggunakannya dalam C atau C ++ demi perlindungan header portabel dan tradisional. Semua preprocessor Objective-C harus menyertakan #import.
Jason Coco
13
Pelindung tajuk adalah tempat Anda menambahkan ke atas: #ifndef myheader #define myheader ... diikuti oleh kode tajuk ...#endif
Tim
359

Tampaknya ada banyak kebingungan mengenai preprosesor.

Apa yang dikompilasi oleh kompiler ketika ia melihat #includebahwa ia menggantikan baris itu dengan isi dari file yang disertakan, tidak ada pertanyaan yang diajukan.

Jadi jika Anda memiliki file a.hdengan konten ini:

typedef int my_number;

dan file b.cdengan konten ini:

#include "a.h"
#include "a.h"

file b.cakan diterjemahkan oleh preprocessor sebelum dikompilasi ke

typedef int my_number;
typedef int my_number;

yang akan menghasilkan kesalahan kompiler, karena jenisnya my_numberdidefinisikan dua kali. Meskipun definisinya sama, ini tidak diizinkan oleh bahasa C.

Karena header sering digunakan di lebih dari satu tempat termasuk penjaga biasanya digunakan dalam C. Ini terlihat seperti ini:

 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif

File b.cmasih akan memiliki seluruh isi header di dalamnya dua kali setelah diproses. Tetapi instance kedua akan diabaikan karena makro _a_h_included_sudah ditentukan.

Ini bekerja dengan sangat baik, tetapi memiliki dua kelemahan. Pertama-tama penjaga menyertakan harus ditulis, dan nama makro harus berbeda di setiap header. Dan kedua kompiler masih harus mencari file header dan membacanya sesering yang disertakan.

Objective-C memiliki #importinstruksi preprocessor (juga dapat digunakan untuk kode C dan C ++ dengan beberapa kompiler dan opsi). Ini hampir sama dengan #include, tetapi juga mencatat secara internal file mana yang sudah dimasukkan. The #importgaris hanya digantikan oleh isi dari nama file untuk pertama kalinya ditemui. Setiap saat setelah itu hanya diabaikan.

Sven
sumber
5
Ini adalah jawaban yang lebih baik daripada yang diterima. @ Guill, Anda harus mengubah jawaban yang diterima.
Nguyen Minh Binh
6
Setelah mengubah 4 #includes menjadi #importpada file header template 7000 baris, ada peningkatan kinerja yang nyata dalam kompilasi dan responsif intellisense XCode. (Saya rasa saya tidak membayangkannya)
bobobobo
63

Saya setuju dengan Jason.

Saya ketahuan melakukan ini:

#import <sys/time.h>  // to use gettimeofday() function
#import <time.h>      // to use time() function

Untuk GNU gcc, ia terus mengeluh bahwa fungsi time () tidak didefinisikan.

Jadi saya mengubah #import menjadi #include dan semuanya berjalan ok.

Alasan:

Anda #import <sys / time.h>:
    <sys / time.h> hanya menyertakan sebagian dari <time.h> dengan menggunakan #defines

Anda #import <time.h>:
    Jangan pergi. Meskipun hanya sebagian dari <time.h> yang sudah disertakan,
    sejauh menyangkut #import, file itu sekarang sudah sepenuhnya disertakan.

Intinya:

C / C ++ header secara tradisional termasuk bagian dari file include lainnya.
Jadi untuk header C / C ++, gunakan #include.
Untuk header objc / objc ++, gunakan #import.

pengguna512705
sumber
2
Tampaknya dentang tidak memiliki masalah yang tidak didefinisikan ini.
ooops
23

#includebekerja seperti C #include.

#importmelacak tajuk mana yang sudah dimasukkan dan diabaikan jika tajuk diimpor lebih dari sekali dalam unit kompilasi. Ini membuatnya tidak perlu menggunakan pelindung tajuk.

Intinya hanya digunakan #importdi Objective-C dan jangan khawatir jika header Anda akhirnya mengimpor sesuatu lebih dari sekali.

Ferruccio
sumber
2
berpura-pura bahwa saya tidak terbiasa dengan C #include (kebanyakan karena saya tidak), apa perbedaan utama antara #include dan #import? Juga, dapatkah Anda memberi tahu saya apa itu pelindung kepala?
Ryan Guill
@Ryan: Lihatlah jawaban Sven.
Adrian Petrescu
13

Saya tahu utas ini sudah lama ... tetapi di "zaman modern" .. ada jauh lebih unggul "termasuk strategi" melalui modul dentang@import - yang sering diabaikan ..

Modul meningkatkan akses ke API pustaka perangkat lunak dengan mengganti model inklusi preprosesor tekstual dengan model semantik yang lebih kuat dan lebih efisien. Dari sudut pandang pengguna, kode hanya terlihat sedikit berbeda, karena seseorang menggunakan deklarasi impor daripada #include preprocessor directive:

@import Darwin; // Like including all of /usr/include. @see /usr/include/module.map

atau

@import Foundation;  //  Like #import <Foundation/Foundation.h>
@import ObjectiveC;  //  Like #import <objc/runtime.h>

Namun, impor modul ini berperilaku sangat berbeda dari #include yang sesuai: ketika kompiler melihat impor modul di atas, ia memuat representasi biner dari modul dan membuat API tersedia untuk aplikasi secara langsung. Definisi preprosesor yang mendahului deklarasi impor tidak berdampak pada API yang disediakan ... karena modul itu sendiri dikompilasi sebagai modul terpisah, mandiri. Selain itu, setiap bendera penghubung yang diperlukan untuk menggunakan modul akan secara otomatis diberikan ketika modul diimpor. Model impor semantik ini mengatasi banyak masalah dari model inklusi preprosesor.

Untuk mengaktifkan modul, berikan flag baris perintah -fmodulesalias CLANG_ENABLE_MODULESdi Xcode- pada waktu kompilasi. Seperti disebutkan di atas .. strategi ini menyingkirkan APA PUN dan SEMUA LDFLAGS. Seperti di, Anda dapat MENGHAPUS pengaturan "OTHER_LDFLAGS" apa pun, serta setiap fase "Menautkan" ..

masukkan deskripsi gambar di sini

Saya menemukan waktu kompilasi / peluncuran untuk "merasa" jauh lebih tajam (atau mungkin, hanya ada sedikit jeda saat "menautkan"?) .. dan juga, memberikan peluang besar untuk membersihkan file Project-Prefix.pch yang sekarang asing, dan sesuai pengaturan membangun, GCC_INCREASE_PRECOMPILED_HEADER_SHARING, GCC_PRECOMPILE_PREFIX_HEADER, dan GCC_PREFIX_HEADER, dll

Selain itu, walaupun tidak didokumentasikan dengan baik ... Anda dapat membuat module.maps untuk kerangka kerja Anda sendiri dan memasukkannya dengan cara yang nyaman. Anda dapat melihat repo github Modul ObjC-Dentang saya untuk beberapa contoh bagaimana menerapkan mukjizat tersebut.

Alex Gray
sumber
4

Jika Anda terbiasa dengan C ++ dan makro, maka

#import "Class.h" 

mirip dengan

{
#pragma once

#include "class.h"
}

yang berarti bahwa Kelas Anda akan dimuat hanya sekali ketika aplikasi Anda berjalan.

Gerbang Evol
sumber
Apakah ini penggunaan #pragma yang didukung sekali? Saya selalu berpikir pragma harus ada di dalam file ed yang disertakan untuk bekerja.
uliwitness
@ Andrewitness Anda benar. #pragma onceditempatkan di file yang disertakan, bukan file yang melakukan menyertakan. -1 untuk itu.
herzbube
1

Mungkin saya memiliki variabel global di salah satu .hfile saya yang menyebabkan masalah, dan saya menyelesaikannya dengan menambahkan externdi depannya.

neowinston
sumber
0

JIKA Anda memasukkan file dua kali dalam file .h daripada compiler akan memberikan kesalahan. Tetapi jika Anda #memasukkan file lebih dari satu kali kompiler akan mengabaikannya.

Husmukh
sumber
8
#includefile yang sama dua kali tidak menghasilkan kesalahan.
kennytm
1
Untuk melengkapi komentar @ KennyTM, # memasukkan file yang sama dua kali dalam header yang sama tidak menghasilkan kesalahan kompilasi JIKA header header yang biasa (#ifndef FILE_NAME_H #define FILE_NAME_H #end) ada di sana. Ini latihan yang diharapkan. Menggunakan #import, penjaga tajuk tidak diperlukan.
jbat100
@ jbat100: #includehanyalah mekanisme salin dan tempel. Ada penggunaan yang disengaja #includelebih dari sekali tanpa menyertakan penjaga, misalnya "X makro".
kennytm
Menyertakan file dua kali dapat menyebabkan kesalahan tergantung pada apa yang Anda sertakan. Saya telah melihat kode C yang digunakan #includeuntuk mengimplementasikan semacam template. Mereka melakukan #define, termasuk header, #undefd dan redid the #define, termasuk header yang sama untuk kedua kalinya. Ini mengakibatkan kode menjadi parameter, valid, dan dimasukkan dua kali, karena nilai dari definisinya berbeda. Jadi ada keuntungan menggunakan #include, tetapi jika Anda menggunakan bahasa modern seperti C ++ atau ObjC, Anda biasanya tidak memerlukan ini.
saksi mata
0

#includeitu digunakan untuk mendapatkan "hal-hal" dari file lain ke yang #includedigunakan. Ex:

dalam file: main.cpp

#include "otherfile.h"

// some stuff here using otherfile.h objects,
// functions or classes declared inside

Header guard digunakan di bagian atas setiap file header (* .h) untuk mencegah memasukkan file yang sama lebih dari satu kali (jika itu terjadi Anda akan mendapatkan kesalahan kompilasi).

dalam file: otherfile.h

#ifndef OTHERFILE
#define OTHERFILE

// declare functions, classes or objects here

#endif

bahkan jika Anda meletakkan #include"otherfile.h" n waktu dalam kode Anda, ini di dalamnya tidak akan dideklarasikan ulang.

Celso Dantas
sumber
0
#include + guard == #import

#include guardWiki - pelindung makro, pelindung tajuk atau pelindung file mencegah penggandaan tajuk dengan tandapreprocessoryang dapat memperlambat waktu pembuatan

Langkah selanjutnya adalah

.pch[Tentang] =>@import [Tentang]

[# impor dalam .hatau .m]

yoAlex5
sumber