ความแตกต่างระหว่าง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 จะรักษาตัวแทนภาพเคลื่อนไหว)