เป็นวิธีที่ดีที่สุดในการสร้างค่าคงที่ใน Objective-C


156

ฉันกำลังสร้างลูกค้า Reddit เพื่อการเรียนรู้ ฉันต้องมีไฟล์ที่มีค่าคงที่อยู่ด้วย ฉันคิดเกี่ยวกับการนำเข้าไฟล์ในReddit-Prefix.pchไฟล์เพื่อให้ค่าคงที่พร้อมใช้งานสำหรับไฟล์ทั้งหมด มันเป็นวิธีที่ดีในการทำสิ่งต่าง ๆ ? นอกจากนี้ฉันได้ทำวิจัยของฉันและพบวิธีการหลายวิธีในการสร้างค่าคงที่ แต่ฉันไม่รู้ว่าควรใช้วิธีใด:

  • #define แมโคร
  • const
  • static const
  • extern const
  • enum

ดังนั้นวิธีใดเป็นวิธีที่ต้องการ การประชุมคืออะไร? ฉันรู้ว่า "มันขึ้นอยู่กับ" แต่คำถามของฉันโดยเฉพาะคือ: กรณีการใช้งานสำหรับการแก้ปัญหาเหล่านั้นคืออะไร?

นอกจากนี้หากใช้extern constฉันต้องนำเข้าไฟล์มิเช่นนั้นค่าคงที่จะพร้อมใช้งานทั่วโลกโดยไม่ต้องนำเข้าไฟล์หรือไม่

สิ่งหนึ่งที่ฉันสามารถสรุปได้อย่างมีเหตุผลคือenumเป็นตัวเลือกที่ดีที่สุดเมื่อกำหนดบางสิ่งเช่นโดเมนข้อผิดพลาดที่กำหนดเอง (ฉันจริงใช่ไหม) แต่แล้วคนอื่น ๆ ล่ะ?


stackoverflow.com/questions/11153156/…โปรดไปที่ลิงก์นี้ ... โซลูชันของคุณอยู่ในบทความนี้
ผู้ใช้ 1531343

3
@BhavikKama: นั่นเป็นคำถามที่แคบกว่าซึ่งแตกต่างจากโซลูชันสองอย่าง
ปีเตอร์โฮเชยา

สำหรับ - const แบบคงที่, #define, enum, ลิงก์นี้มีประโยชน์stackoverflow.com/questions/1674032/static-const-vs-define-in-cที่ให้คำอธิบายที่ดีเกี่ยวกับ 3 ทางเลือกของ const
ผู้ใช้ 1531343

enumมีประโยชน์สำหรับค่าที่สำคัญเท่านั้น #defineและค่าคงที่สามารถเป็นชนิดข้อมูลใดก็ได้
rmaddy

const,, static constและextern constเหมือนกันทั้งหมดยกเว้นขอบเขต ดังนั้นจึงมีเพียงสามตัวเลือกเท่านั้น
rmaddy

คำตอบ:


385

คำถามแรกคือขอบเขตที่คุณต้องการให้ค่าคงที่ของคุณมีอยู่ซึ่งเป็นสองคำถาม:

  • ค่าคงที่เหล่านี้เป็นค่าเฉพาะสำหรับชั้นเรียนเดียวหรือไม่หรือมีเหตุผลที่จะให้พวกมันมีอยู่ทั่วแอปพลิเคชัน?
  • หากพวกเขาเป็นคลาสเฉพาะพวกเขาจะใช้สำหรับลูกค้าของชั้นเรียนหรือเฉพาะภายในชั้นเรียน?

หากพวกเขาเฉพาะและภายในชั้นเดียวประกาศพวกเขาเป็นstatic constที่ด้านบนของไฟล์. m เช่น:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

หากพวกเขาเกี่ยวข้องกับชั้นเดียว แต่ควรเป็นสาธารณะ / ใช้โดยชั้นเรียนอื่น ๆ ประกาศพวกเขาเช่นเดียวกับexternในส่วนหัวและกำหนดไว้ใน. m:

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

หากพวกเขาควรจะเป็นระดับโลกประกาศพวกเขาในส่วนหัวและกำหนดพวกเขาในโมดูลที่เกี่ยวข้องโดยเฉพาะสำหรับค่าคงที่เหล่านั้น

คุณสามารถผสมและจับคู่สิ่งเหล่านี้กับค่าคงที่ต่างกันด้วยระดับที่แตกต่างกันของระดับโลกที่คุณต้องการให้เป็นและสำหรับค่าคงที่ระดับโลกที่แตกต่างกันซึ่งไม่ได้อยู่ด้วยกัน - คุณสามารถใส่พวกมันไว้ในโมดูลแยกต่างหาก ต้องการ.

ทำไม#defineล่ะ

คำตอบเก่าคือ“ มาโครไม่มีข้อมูลประเภท” แต่คอมไพเลอร์ในวันนี้ค่อนข้างฉลาดในการทำการตรวจสอบตัวอักษรทุกชนิด (มาโครตัวใดขยาย) และตัวแปร

คำตอบที่ทันสมัยเป็นเพราะดีบักเกอร์ไม่รู้จักมาโครของคุณ คุณไม่สามารถพูด[myThing addObserver:self forKey:MyThingNotificationKey]ในคำสั่งดีบักเกอร์ได้ถ้าMyThingNotificationKeyเป็นมาโคร โปรแกรมดีบั๊กสามารถรู้ได้ถ้ามันเป็นตัวแปร

ทำไมenumล่ะ

rmaddy เอาชนะฉันได้ในความคิดเห็น: enumสามารถกำหนดค่าคงที่จำนวนเต็มเท่านั้น สิ่งต่าง ๆ เช่นหมายเลขตัวระบุอนุกรมบิตมาสก์รหัสสี่ไบต์ ฯลฯ

สำหรับวัตถุประสงค์เหล่านั้นenumดีมากและคุณควรใช้มันอย่างแน่นอน (ดียิ่งขึ้นใช้และแมโคร .) สำหรับสิ่งอื่น ๆ ที่คุณจะต้องใช้อย่างอื่นนั้น ไม่ได้ทำอะไรนอกจากจำนวนเต็มNS_ENUMNS_OPTIONSenum

และคำถามอื่น ๆ

ฉันคิดเกี่ยวกับการนำเข้าไฟล์ในไฟล์ Reddit-Prefix.pch เพื่อให้ค่าคงที่พร้อมใช้งานสำหรับไฟล์ทั้งหมด มันเป็นวิธีที่ดีในการทำสิ่งต่าง ๆ ?

อาจไม่เป็นอันตราย แต่อาจมากเกินไป นำเข้าส่วนหัวค่าคงที่ที่คุณต้องการ

กรณีการใช้งานสำหรับโซลูชันแต่ละรายการมีอะไรบ้าง

  • #define: ค่อนข้าง จำกัด ฉันไม่แน่ใจว่ามีเหตุผลที่ดีที่จะใช้สิ่งนี้กับค่าคงที่อีกต่อไป
  • const: ดีที่สุดสำหรับค่าคงที่ในท้องถิ่น นอกจากนี้คุณต้องใช้สิ่งนี้กับสิ่งที่คุณประกาศไว้ในส่วนหัวและตอนนี้กำลังกำหนด
  • static const: ดีที่สุดสำหรับค่าคงที่ของไฟล์ (หรือคลาสเฉพาะ)
  • extern const: คุณต้องใช้สิ่งนี้เมื่อส่งออกค่าคงที่ในส่วนหัว

นอกจากนี้หากใช้extern constฉันต้องนำเข้าไฟล์มิเช่นนั้นค่าคงที่จะพร้อมใช้งานทั่วโลกโดยไม่ต้องนำเข้าไฟล์หรือไม่

คุณต้องนำเข้าไฟล์ไม่ว่าจะในแต่ละไฟล์ที่คุณใช้หรือในส่วนหัวของคำนำหน้า


3
ทำไมไม่ใช้static NSString *constใน.hไฟล์ทั้งหมด?
Iulian Onofrei

3
@IulianOnofrei: คุณทำได้ถ้าอยู่ในแอปพลิเคชันไม่ใช่เฟรมเวิร์ก หากคุณทำเช่นstatic NSString *const foo = @"foo";นั้นส่วนหัวของคุณจะกำหนดว่าสตริงคืออะไรและจะต้องเหมือนกันทุกที่ - หากคุณเคยเปลี่ยนสตริงและบุคคลอื่นใช้เวอร์ชันที่แตกต่างกันของส่วนหัวด้วยสตริงที่แตกต่างกันสตริงจะไม่ตรงกันเมื่อทำงาน เวลา. ในเฟรมเวิร์กคุณต้องการให้การเข้าถึงสัญลักษณ์เท่านั้นและให้เฟรมเวิร์กเป็นแหล่งเดียวของมูลค่าที่แท้จริงของสัญลักษณ์นั้นเพื่อให้ทุกคนได้รับสตริงเดียวกันจากที่เดียว นั่นคือสิ่งที่externทำให้คุณได้รับ
Peter Hosey

หมายเหตุเพิ่มเติมเกี่ยวกับ#defines: พวกเขาไม่รับประกันว่าจะมีที่อยู่เดียวกันในหน่วยความจำ (ขึ้นอยู่กับว่าพวกเขาประกาศอย่างไรพวกเขาอาจจัดสรรอินสแตนซ์ใหม่ทุกครั้งที่ใช้) ดังนั้นการใช้งานmyObject == MyDefineอาจไม่ได้ผลตามที่คาดหวัง แต่myObject == MyStaticConstจะ
Ben Leggiero

มันมีความหมายในการสะกดคำเช่นstatic NSString *constแทนที่จะstatic NSString const*? ความแตกต่างใด ๆ !
kokos8998

@ kokos8998 มันสร้างความแตกต่างหรือไม่? ใช่แล้ว. static NSString const *เป็นเช่นเดียวกับstatic const NSString *และหมายถึง "a (เปลี่ยนแปลง) ตัวชี้ไปยังค่าคงที่ NSString" - ซึ่งไม่มีประโยชน์อะไรที่นี่เนื่องจาก NSString ไม่มีการเปลี่ยนแปลง สิ่งที่คุณต้องการเท่านั้นstatic NSString * const- ซึ่งเป็น "ตัวชี้คงที่ไปยัง NSString"
เดวิด

8

FOUNDATION_EXPORT

พิจารณาใช้FOUNDATION_EXPORTสำหรับความเข้ากันได้มากกว่าที่externกำหนดไว้ในพื้นฐานและคอมไพล์เป็นรูปแบบที่เข้ากันได้สำหรับ C, C ++ และ Win32

ตามที่กำหนดไว้ใน NSObjCRuntime.h

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif

#if TARGET_OS_WIN32

    #if defined(NSBUILDINGFOUNDATION)
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
    #else
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
    #endif

    #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)

#else
    #define FOUNDATION_EXPORT  FOUNDATION_EXTERN
    #define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.