จะเกิดอะไรขึ้นหากหมวดหมู่ ObjC สองหมวดหมู่แทนที่วิธีการเดียวกัน

ฉันรู้กฎสองสามข้อเกี่ยวกับหมวดหมู่ Objective-C:

  1. วิธีการหมวดหมู่ไม่ควรแทนที่วิธีการที่มีอยู่ (คลาสหรืออินสแตนซ์)
  2. หมวดหมู่ ที่แตกต่างกัน สองหมวดหมู่ที่ใช้วิธีการเดียวกันสำหรับคลาสเดียวกันจะส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนดไว้

ฉันต้องการทราบว่าจะเกิดอะไรขึ้นเมื่อฉันแทนที่วิธีการจัดหมวดหมู่ของฉันเองในหมวดหมู่เดียวกัน ตัวอย่างเช่น:

@interface NSView (MyExtensions)
- (void)foo; // NSView category implementation
@end

@interface MyClass : NSView
{ }
@end

@interface MyClass (MyExtensions)
- (void)foo; // MyClass category implementation
@end

เมื่อกำหนดอินเทอร์เฟซเหล่านี้แล้ว วิธีใดที่จะถูกดำเนินการเมื่อฉันรันโค้ดต่อไปนี้

MyClass * instance = [[MyClass alloc] initWith...];
[instance foo];
[instance release];

หมายเหตุ: สำหรับคอมไพเลอร์ของฉัน การใช้งาน MyClass จะมีความสำคัญกว่า แต่ฉันไม่แน่ใจว่าจะรับประกันว่าจะเกิดขึ้นหรือไม่ หรือเป็นเพียงลักษณะเฉพาะของพฤติกรรมที่ไม่ได้กำหนดไว้เท่านั้น


person e.James    schedule 11.07.2010    source แหล่งที่มา


คำตอบ (2)


แต่ละวิธีของแต่ละคลาสมีการนำไปปฏิบัติ หมวดหมู่จะเพิ่มหรือแทนที่วิธีการสำหรับชั้นเรียนเฉพาะ นั่นหมายถึงพฤติกรรมที่คุณเห็น โดยที่ MyClass มีหนึ่ง foo และ NSView มีอีก foo ได้รับการกำหนดไว้อย่างดี อินสแตนซ์ใดๆ ของ MyClass จะมี foo ที่แตกต่างจากอินสแตนซ์ใดๆ ของ NSView ที่ไม่ใช่ MyClass เช่นเดียวกับที่ foo ถูกกำหนดไว้ในการใช้งานหลัก ไม่ใช่หมวดหมู่ คุณควรจะสามารถโทร [super foo] จาก MyClass เพื่อเข้าถึง foo ที่กำหนดไว้สำหรับ NSView

person drawnonward    schedule 11.07.2010
comment
ถูกต้องหรือไม่ที่จะแทนที่ในวิธีการ Category ที่ประกาศและนำไปใช้ใน Category ของ super class - person BergP; 19.03.2013

หากต้องการขยายคำตอบที่ดึงออกมา:

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

อะไรก็ตามที่คุณสามารถทำได้ในอินเทอร์เฟซของคลาสปกติ คุณก็สามารถทำได้ในหมวดหมู่ และสิ่งที่คุณ ไม่ควร ทำในอินเทอร์เฟซของคลาสปกติ ที่คุณไม่ควรทำในหมวดหมู่

So:

วิธีการหมวดหมู่ไม่ควรแทนที่วิธีการที่มีอยู่ (คลาสหรืออินสแตนซ์)

คุณสามารถใช้เมธอดที่กำหนดไว้ในอินเทอร์เฟซคลาสปกติเพื่อแทนที่เมธอด สืบทอดมา เพื่อให้คุณสามารถแทนที่เมธอดที่สืบทอดมาในหมวดหมู่ได้

อย่างไรก็ตาม คุณจะไม่มีวันพยายามที่จะมีคำจำกัดความของวิธีการที่เหมือนกันสองคำในอินเทอร์เฟซธรรมดาเดียวกัน ดังนั้นคุณไม่ควรมีวิธีในหมวดหมู่ที่มีชื่อเดียวกันกับวิธีการในอินเทอร์เฟซทั่วไปหรือหมวดหมู่อื่นในคลาสเดียวกัน เนื่องจากคำจำกัดความของเมธอดทั้งหมดจบลงในไฟล์ที่คอมไพล์เดียวกัน จึงเห็นได้ชัดว่าขัดแย้งกัน

หมวดหมู่ที่แตกต่างกันสองประเภทที่ใช้วิธีการเดียวกันส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนดไว้

ควรเขียนใหม่เพื่อพูดว่า "หมวดหมู่ที่แตกต่างกันสองหมวดหมู่ที่ใช้วิธีการเดียวกัน สำหรับคลาสเดียวกัน ส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนดไว้" ขอย้ำอีกครั้ง เนื่องจากวิธีการทั้งหมดของคลาสใดคลาสหนึ่งจบลงในไฟล์เดียวกัน การมีสองวิธีในคลาสเดียวกันจะทำให้เกิดความแปลกประหลาดอย่างเห็นได้ชัด

คุณสามารถใช้หมวดหมู่เพื่อจัดเตรียมวิธีการที่แทนที่วิธีซูเปอร์คลาสได้ เนื่องจากคลาสและซูเปอร์คลาสนั้นเป็นคลาสที่แตกต่างกันสองคลาส

หากคุณเคยสับสนว่าหมวดหมู่ใดจะสร้างปัญหาหรือไม่ ให้ถามตัวเองว่า: "วิธีการในหมวดหมู่นั้นจะใช้งานได้หรือไม่ หากฉันคัดลอกและวางมันทั้งหมดลงในไฟล์ .h/.m ของคลาส" หากคำตอบคือ "ใช่" คุณก็ชัดเจนแล้ว ถ้า "ไม่" แสดงว่าคุณมีปัญหา

person TechZen    schedule 11.07.2010
comment
+1 ขอบคุณ. นั่นเป็นวิธีอธิบายที่ดีมาก ฉันยังได้เปลี่ยนถ้อยคำในกฎข้อ 2 ให้ตรงกับของคุณด้วย - person e.James; 11.07.2010