ความแตกต่างระหว่างidและvoid *คืออะไร?
ความแตกต่างระหว่างidและvoid *คืออะไร?
คำตอบ:
void * หมายถึง "การอ้างอิงถึงหน่วยความจำบางส่วนแบบสุ่มที่มีเนื้อหาที่ไม่ได้พิมพ์ / ไม่รู้จัก"
id หมายถึง "การอ้างอิงถึงบาง Objective-C วัตถุของคลาสที่ไม่รู้จัก"
มีความแตกต่างทางความหมายเพิ่มเติม:
ภายใต้ GC เท่านั้นหรือ GC โหมดสนับสนุนคอมไพเลอร์จะปล่อยอุปสรรคเขียนอ้างอิงจากประเภทแต่ไม่สำหรับประเภทid void *เมื่อประกาศโครงสร้างสิ่งนี้อาจเป็นความแตกต่างที่สำคัญ การประกาศ iVars เช่นvoid *_superPrivateDoNotTouch;นั้นจะทำให้เกิดการเก็บเกี่ยววัตถุก่อนกำหนดหาก_superPrivateDoNotTouchจริง ๆ แล้วเป็นวัตถุ อย่าทำอย่างนั้น
ความพยายามที่จะเรียกใช้เมธอดบนการอ้างอิงvoid *ชนิดจะทำให้เกิดคำเตือนคอมไพเลอร์
ความพยายามที่จะเรียกใช้เมธอดบนidชนิดจะเตือนเฉพาะเมื่อเมธอดที่ถูกเรียกนั้นไม่ได้ถูกประกาศในการประกาศใด ๆ@interfaceที่คอมไพเลอร์เห็น
void *ดังนั้นหนึ่งไม่ควรอ้างถึงวัตถุที่เป็นหนึ่ง ในทำนองเดียวกันเราควรหลีกเลี่ยงการใช้idตัวแปรที่พิมพ์เพื่ออ้างถึงวัตถุ ใช้การอ้างอิงคลาสที่เฉพาะเจาะจงมากที่สุดที่คุณสามารถทำได้ แม้NSObject *จะดีกว่าidเพราะอย่างน้อยที่สุดคอมไพเลอร์สามารถให้การตรวจสอบความถูกต้องของการเรียกใช้เมธอดเทียบกับการอ้างอิงนั้นได้ดีขึ้น
การใช้งานทั่วไปอย่างหนึ่งที่ถูกต้องvoid *คือการอ้างอิงข้อมูลทึบแสงที่ส่งผ่าน API อื่น
พิจารณาsortedArrayUsingFunction: context:วิธีการNSArray:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
ฟังก์ชันการเรียงลำดับจะถูกประกาศเป็น:
NSInteger mySortFunc(id left, id right, void *context) { ...; }
ในกรณีนี้ NSArray จะส่งผ่านสิ่งที่คุณส่งผ่านเป็นcontextอาร์กิวเมนต์ไปยังวิธีที่ผ่านเป็นcontextอาร์กิวเมนต์ มันเป็นก้อนขนาดทึบข้อมูลขนาดตัวชี้เท่าที่ NSArray เป็นห่วงและคุณมีอิสระที่จะใช้เพื่อวัตถุประสงค์ใดก็ตามที่คุณต้องการ
หากไม่มีคุณสมบัติการปิดในภาษานี่เป็นวิธีเดียวที่จะพกพาข้อมูลขนาดใหญ่ไปพร้อมกับฟังก์ชั่น ตัวอย่าง; หากคุณต้องการให้ mySortFunc () เรียงลำดับตามตัวพิมพ์เล็กและใหญ่โดยไม่คำนึงถึงขนาดตัวพิมพ์เล็กและตัวพิมพ์เล็กในขณะที่ยังคงปลอดภัยต่อเธรด
เปราะบางและผิดพลาดได้ง่าย แต่วิธีเดียว
บล็อกแก้ปัญหานี้ - บล็อกปิดสำหรับ C. มีอยู่ใน Clang - http://llvm.org/และแพร่หลายใน Snow Leopard ( http://developer.apple.com/library/ios/documentation/Performance) /Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf )
idตอบสนองได้ สามารถอ้างถึงตัวอย่างของการเรียนที่ไม่ได้มาจากธรรมชาติid NSObjectอย่างไรก็ตามคำพูดของคุณในทางปฏิบัติจะตรงกับพฤติกรรมโลกแห่งความเป็นจริงมากที่สุด คุณไม่สามารถผสม<NSObject>คลาสที่ไม่ได้ใช้งานกับ Foundation API และไปได้ไกลนั่นคือแน่นอน!
idและClassชนิดจะได้รับการปฏิบัติเป็นตัวชี้วัตถุที่เก็บรักษาไว้ภายใต้ ARC ดังนั้นสมมติฐานจึงเป็นจริงอย่างน้อยภายใต้ ARC
id เป็นตัวชี้ไปยังวัตถุ C วัตถุประสงค์ที่เป็นโมฆะ * เป็นตัวชี้ไปที่อะไร
id ยังปิดคำเตือนที่เกี่ยวข้องกับการโทร mthods ที่ไม่รู้จักดังนั้นตัวอย่างเช่น:
[(id)obj doSomethingWeirdYouveNeverHeardOf];
จะไม่ให้คำเตือนตามปกติเกี่ยวกับวิธีการที่ไม่รู้จัก แน่นอนว่าจะเพิ่มข้อยกเว้น ณ รันไทม์ยกเว้นว่า obj ไม่มีค่าหรือใช้วิธีการนั้นจริงๆ
บ่อยครั้งที่คุณควรใช้NSObject*หรือid<NSObject>ตั้งค่าidอย่างน้อยที่สุดยืนยันว่าวัตถุที่ส่งคืนเป็นวัตถุโกโก้ดังนั้นคุณจึงสามารถใช้วิธีการต่างๆเช่นเก็บรักษา / ปล่อย / เลิกอัตโนมัติโดยอัตโนมัติ
Often you should use NSObject* idโดยการระบุว่าNSObject*คุณกำลังบอกอย่างชัดเจนว่าวัตถุนั้นเป็น NSObject การเรียกใช้เมธอดไปยังวัตถุใด ๆ จะส่งผลให้เกิดการเตือน แต่ไม่มีข้อยกเว้นรันไทม์ตราบเท่าที่วัตถุนั้นตอบสนองการเรียกเมธอด เห็นได้ชัดว่าคำเตือนน่ารำคาญดังนั้นidดีกว่า คุณสามารถระบุให้ชัดเจนยิ่งขึ้นโดยการพูดอย่างหยาบid<MKAnnotation>ซึ่งในกรณีนี้หมายถึงสิ่งใดก็ตามวัตถุนั้นจะต้องสอดคล้องกับโปรโตคอล MKAnnotation
หากวิธีการมีชนิดส่งคืนของidคุณอาจส่งคืนวัตถุ Objective-C ใด ๆ
void หมายความว่าวิธีจะไม่ส่งคืนสิ่งใด
void *เป็นเพียงตัวชี้ คุณจะไม่สามารถแก้ไขเนื้อหาในที่อยู่ที่ตัวชี้ชี้ไป
idเป็นตัวชี้ไปยังวัตถุ Objective-C void *เป็นตัวชี้เพื่ออะไร คุณสามารถใช้void *แทนidแต่ไม่แนะนำเพราะคุณจะไม่ได้รับคำเตือนของคอมไพเลอร์สำหรับสิ่งใด
คุณอาจต้องการดูstackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobjectและunixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs -id.html
void *ตัวแปรที่พิมพ์มากที่สุดแน่นอนสามารถเป็นเป้าหมายของวิธีการ invocations- มันเป็นคำเตือนไม่ใช่ข้อผิดพลาด ไม่เพียง แต่ที่คุณสามารถทำสิ่งนี้และตามด้วย:int i = (int)@"Hello, string!"; printf("Sending to an int: '%s'\n", [i UTF8String]);มันเป็นคำเตือนไม่ใช่ข้อผิดพลาด (และไม่แนะนำอย่างแน่นอนหรือพกพา) แต่เหตุผลที่คุณสามารถทำสิ่งเหล่านี้ได้นั้นเป็นพื้นฐานขั้นพื้นฐานทั้งหมด
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
รหัสข้างต้นมาจาก objc.h ดังนั้นดูเหมือนว่า id เป็นตัวอย่างของ objc_object struct และตัวชี้ isa สามารถผูกกับวัตถุคลาส C Objective ใด ๆ ในขณะที่โมฆะ * เป็นเพียงตัวชี้ที่ไม่ได้พิมพ์
ความเข้าใจของฉันคือ id แสดงถึงตัวชี้ไปยังวัตถุในขณะที่โมฆะ * สามารถชี้ไปที่สิ่งใด ๆ จริง ๆ ตราบใดที่คุณโยนมันไปยังประเภทที่คุณต้องการใช้เป็น
นอกเหนือจากสิ่งที่ได้กล่าวไปแล้วมีความแตกต่างระหว่างวัตถุและตัวชี้ที่เกี่ยวข้องกับคอลเลกชัน ตัวอย่างเช่นหากคุณต้องการใส่บางสิ่งลงใน NSArray คุณต้องมีวัตถุ (ชนิด "id") และคุณไม่สามารถใช้ตัวชี้ข้อมูลดิบที่นั่น (ประเภท "void *") คุณสามารถใช้[NSValue valueWithPointer:rawData]เพื่อแปลงvoid *rawDdataเป็น "id" เพื่อใช้ภายในคอลเลกชัน โดยทั่วไป "id" มีความยืดหยุ่นมากขึ้นและมีความหมายมากขึ้นเกี่ยวกับวัตถุที่แนบมา มีตัวอย่างอื่น ๆ อธิบายเป็นรหัสประเภทของวัตถุประสงค์ C ที่นี่
idจะถือว่ามีการตอบสนอง-retainและ-releaseในขณะที่ avoid*ทึบแสงอย่างสมบูรณ์เพื่อ callee คุณไม่สามารถส่งตัวชี้ไปยัง-performSelector:withObject:afterDelay:(มันเก็บรักษาวัตถุ) และคุณไม่สามารถสันนิษฐานได้ว่า+[UIView beginAnimations:context:]จะรักษาบริบทไว้ (ตัวแทนภาพเคลื่อนไหวควรรักษาความเป็นเจ้าของบริบทไว้ UIKit จะรักษาตัวแทนภาพเคลื่อนไหว)