วิธีการลบล้างโดยใช้หมวดหมู่ใน Objective-C


87

ฉันสามารถใช้หมวดหมู่คลาสเพื่อแทนที่เมธอดที่ใช้อยู่แล้วโดยใช้หมวดหมู่ได้หรือไม่ แบบนี้:

1) วิธีการเดิม

-(BOOL) method {
  return true;
}

2) วิธีการแทนที่

-(BOOL) method {
  NSLog(@"error?"); 
  return true; 
}

จะได้ผลหรือผิดกฎหมาย?

คำตอบ:


147

จากเอกสารของ Apple :

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

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

  • หมวดหมู่ไม่สามารถแทนที่เมธอดที่ประกาศในหมวดหมู่อื่นของคลาสเดียวกันได้อย่างน่าเชื่อถือ

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

  • การมีอยู่ของเมธอดหมวดหมู่บางอย่างอาจทำให้เกิดการเปลี่ยนแปลงพฤติกรรมในทุกเฟรมเวิร์ก ตัวอย่างเช่นหากคุณแทนที่windowWillClose:วิธีการมอบหมายในหมวดหมู่บน NSObject ผู้รับมอบสิทธิ์หน้าต่างทั้งหมดในโปรแกรมของคุณจะตอบสนองโดยใช้วิธีการประเภท พฤติกรรมของอินสแตนซ์ NSWindow ทั้งหมดของคุณอาจเปลี่ยนไป หมวดหมู่ที่คุณเพิ่มในคลาสของเฟรมเวิร์กอาจทำให้เกิดการเปลี่ยนแปลงพฤติกรรมอย่างลึกลับและนำไปสู่ข้อขัดข้อง


ขอบคุณ แต่ฉันรู้แล้ว ฉันแค่สงสัยว่าคดีของฉันถูกกฎหมายหรือไม่ กรณีของฉันแตกต่างจากเอกสารเล็กน้อย :)
แก้ไข

ทำไมมันถึงแตกต่างกัน? เอกสารบอกว่าถูกต้องตามกฎหมายหากวิธีการเดิมไม่อยู่ในหมวดหมู่ แต่ไม่แนะนำอย่างยิ่ง แล้วคุณจะทำได้ ...
Benoît

1
ขอบคุณสำหรับคำแนะนำ ฉันยากจนในภาษานี้ ฉันได้รับข้อมูลใหม่จากคุณ
แก้ไข

1
ถูกต้องหรือไม่ที่จะแทนที่ในเมธอด Category ที่ประกาศและนำไปใช้ใน Category ของ super class?
BergP

2
ลิงก์เสียนี่คือเวอร์ชันใหม่หรือไม่ developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…
RndmTsk


9

ลิงก์เอกสารเก่าหมดแล้ว สิ่งทดแทนที่ดีที่สุดที่ฉันสามารถหาได้คือที่นี่: Apple Docs :

หลีกเลี่ยงการปะทะกันของชื่อวิธีหมวดหมู่

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

หากชื่อของเมธอดที่ประกาศในหมวดหมู่นั้นเหมือนกับเมธอดในคลาสดั้งเดิมหรือเมธอดในหมวดหมู่อื่นในคลาสเดียวกัน (หรือแม้แต่ซูเปอร์คลาส) พฤติกรรมจะไม่ได้กำหนดว่าจะใช้เมธอดใดที่ รันไทม์ สิ่งนี้มีโอกาสน้อยที่จะเป็นปัญหาหากคุณใช้หมวดหมู่กับชั้นเรียนของคุณเอง แต่อาจทำให้เกิดปัญหาเมื่อใช้หมวดหมู่เพื่อเพิ่มวิธีการในคลาส Cocoa หรือ Cocoa Touch มาตรฐาน

มันคือ Apple ที่ใช้การสัมผัสที่เบากว่า แต่ประเด็นหลักเหมือนกันนั่นคือคุณเชิญหายนะเพราะพฤติกรรมที่คาดเดาไม่ได้นั้นเงียบ


2

สิ่งสำคัญคือต้องทราบว่าหมวดหมู่ยังสามารถใช้เพื่อแทนที่เมธอดที่มีอยู่ในคลาสพื้นฐานได้ (เช่นวิธีการขับเคลื่อนของคลาสรถยนต์) แต่คุณไม่ควรทำเช่นนี้ ปัญหาคือหมวดหมู่เป็นโครงสร้างองค์กรที่เรียบ หากคุณลบล้างวิธีการที่มีอยู่ใน Car + Maintenance.m แล้วตัดสินใจว่าคุณต้องการเปลี่ยนพฤติกรรมอีกครั้งด้วยหมวดหมู่อื่นไม่มีทางที่ Objective-C จะทราบว่าจะใช้การนำไปใช้งานใด การคลาสย่อยมักจะเป็นตัวเลือกที่ดีกว่าในสถานการณ์เช่นนี้

จากบทช่วยสอนนี้http://rypress.com/tutorials/objective-c/categories

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