แม้ว่าฉันคิดว่าฉันสามารถตอบคำถามของคุณได้ แต่ก็ไม่ใช่คำตอบที่คุณต้องการ
TL; DR: @objc
ฟังก์ชันอาจไม่อยู่ในส่วนขยายโปรโตคอล คุณสามารถสร้างคลาสพื้นฐานแทนได้แม้ว่านั่นจะไม่ใช่ทางออกที่ดี
ส่วนขยายโปรโตคอลและวัตถุประสงค์ -C
ประการแรกคำถาม / คำตอบนี้ ( สามารถใช้วิธี Swift ที่กำหนดบนส่วนขยายบนโปรโตคอลที่เข้าถึงใน Objective-c ) ดูเหมือนจะแนะนำว่าเนื่องจากวิธีการส่งส่วนขยายโปรโตคอลภายใต้ประทุนวิธีการที่ประกาศในส่วนขยายโปรโตคอลจะไม่ปรากฏในobjc_msgSend()
ฟังก์ชันและ ดังนั้นจึงมองไม่เห็นโค้ด Objective-C เนื่องจากเมธอดที่คุณพยายามกำหนดในส่วนขยายของคุณจำเป็นต้องมองเห็น Objective-C (จึงUIKit
สามารถใช้งานได้) มันจึงตะโกนใส่คุณว่าไม่รวม@objc
แต่เมื่อคุณรวมแล้วมันจะตะโกนใส่คุณเพราะ@objc
ไม่ได้รับอนุญาตใน ส่วนขยายโปรโตคอล อาจเป็นเพราะปัจจุบันส่วนขยายโปรโตคอลไม่สามารถมองเห็นได้กับ Objective-C
นอกจากนี้เรายังสามารถเห็นข้อความแสดงข้อผิดพลาดเมื่อเราเพิ่ม @objc
สถานะ "@objc สามารถใช้ได้กับสมาชิกของคลาสโปรโตคอล @objc และส่วนขยายที่เป็นรูปธรรมของคลาสเท่านั้น" นี่ไม่ใช่ชั้นเรียน ส่วนขยายไปยังโปรโตคอล @objc ไม่เหมือนกับการกำหนดโปรโตคอลเอง (เช่นในข้อกำหนด) และคำว่า "คอนกรีต" จะแนะนำว่าส่วนขยายโปรโตคอลไม่นับเป็นส่วนขยายคลาสที่เป็นรูปธรรม
วิธีแก้ปัญหา
น่าเสียดายที่สิ่งนี้ทำให้คุณไม่สามารถใช้ส่วนขยายโปรโตคอลได้อย่างสมบูรณ์เมื่อการใช้งานเริ่มต้นต้องมองเห็นได้ในกรอบ Objective-C ตอนแรกฉันคิดว่าอาจ@objc
ไม่ได้รับอนุญาตในส่วนขยายโปรโตคอลของคุณเนื่องจาก Swift Compiler ไม่สามารถรับประกันได้ว่าประเภทที่สอดคล้องกันจะเป็นคลาส (แม้ว่าคุณจะระบุไว้เป็นพิเศษUIViewController
ก็ตาม) ดังนั้นฉันจึงวางclass
ข้อกำหนดP1
ไว้ สิ่งนี้ไม่ได้ผล
บางทีวิธีแก้ปัญหาเพียงอย่างเดียวคือการใช้คลาสฐานแทนโปรโตคอลที่นี่ แต่เห็นได้ชัดว่าไม่เหมาะอย่างยิ่งเนื่องจากคลาสอาจมีคลาสฐานเดียว แต่สอดคล้องกับโปรโตคอลหลายโปรโตคอล
หากคุณเลือกที่จะไปเส้นทางนี้โปรดคำนึงถึงคำถามนี้ ( Swift 3 ObjC Optional Protocol Method Not called in Subclass ) ดูเหมือนว่าปัญหาปัจจุบันอีกประการหนึ่งใน Swift 3 คือคลาสย่อยจะไม่สืบทอดการใช้งานข้อกำหนดโปรโตคอลเสริมของซูเปอร์คลาสโดยอัตโนมัติ คำตอบสำหรับคำถามนั้นใช้การปรับตัวเป็นพิเศษ@objc
เพื่อหลีกเลี่ยงปัญหานี้
การรายงานปัญหา
ฉันคิดว่าสิ่งนี้กำลังถูกพูดถึงในหมู่ผู้ที่ทำงานในโครงการโอเพ่นซอร์ส Swift แต่คุณสามารถมั่นใจได้ว่าพวกเขารับรู้โดยใช้ Reporter แอปเปิ้ล Bugซึ่งมีแนวโน้มที่ในที่สุดก็จะทำให้ทางกับ Core ทีมสวิฟท์หรือนักข่าวข้อผิดพลาดสวิฟท์ อย่างไรก็ตามสิ่งเหล่านี้อาจพบข้อบกพร่องของคุณกว้างเกินไปหรือเป็นที่รู้กันอยู่แล้ว ทีม Swift อาจพิจารณาสิ่งที่คุณต้องการให้เป็นคุณลักษณะภาษาใหม่ซึ่งในกรณีนี้คุณควรตรวจสอบรายชื่ออีเมลก่อน
อัปเดต
ในเดือนธันวาคม 2559 ฉบับนี้ ได้รับการรายงานไปยังชุมชน Swift ปัญหานี้ยังคงถูกทำเครื่องหมายเป็นเปิดโดยมีลำดับความสำคัญปานกลาง แต่มีการเพิ่มความคิดเห็นต่อไปนี้:
นี้มีจุดมุ่งหมาย ไม่มีวิธีใดในการเพิ่มการใช้งานวิธีการให้กับผู้ใช้งานทุกคนเนื่องจากสามารถเพิ่มส่วนขยายได้หลังจากความสอดคล้องกับโปรโตคอล ฉันคิดว่าเราสามารถอนุญาตได้หากส่วนขยายอยู่ในโมดูลเดียวกับโปรโตคอล
เนื่องจากโปรโตคอลของคุณอยู่ในโมดูลเดียวกับส่วนขยายของคุณอย่างไรก็ตามคุณอาจสามารถทำสิ่งนี้ได้ใน Swift เวอร์ชันอนาคต
อัปเดต 2
ในเดือนกุมภาพันธ์ 2017 ปัญหานี้ถูกปิดอย่างเป็นทางการในฐานะ "จะไม่ทำ" โดยหนึ่งในสมาชิกทีม Swift Core พร้อมข้อความต่อไปนี้:
นี่เป็นความตั้งใจ: ส่วนขยายโปรโตคอลไม่สามารถแนะนำจุดเข้า @objc ได้เนื่องจากข้อ จำกัด ของรันไทม์ Objective-C หากคุณต้องการเพิ่มจุดเข้า @objc ใน NSObject ให้ขยาย NSObject
การขยายNSObject
หรือแม้กระทั่งUIViewController
จะไม่บรรลุสิ่งที่คุณต้องการ แต่น่าเสียดายที่ดูเหมือนว่ามันจะกลายเป็นไปไม่ได้
ในอนาคตระยะยาว (มาก) เราอาจสามารถกำจัดการพึ่งพา@objc
วิธีการทั้งหมดได้ แต่เวลานั้นจะไม่มาในเร็ว ๆ นี้เนื่องจากกรอบ Cocoa ยังไม่ได้เขียนด้วย Swift (และไม่สามารถทำได้จนกว่าจะมี ABI ที่เสถียร) .
อัปเดต 3
ในช่วงฤดูใบไม้ร่วงปี 2019 ปัญหานี้จะกลายเป็นปัญหาน้อยลงเนื่องจากเฟรมเวิร์กของ Apple ถูกเขียนใน Swift มากขึ้นเรื่อย ๆ ตัวอย่างเช่นหากคุณใช้SwiftUI
แทนคุณUIKit
คุณจะหลีกเลี่ยงปัญหาทั้งหมดเพราะ@objc
จะไม่จำเป็นเมื่ออ้างถึงSwiftUI
วิธีการ
กรอบงานของ Apple ที่เขียนด้วย Swift ได้แก่ :
- SwiftUI
- RealityKit
- รวมกัน
- CryptoKit
ใคร ๆ ก็คาดหวังว่ารูปแบบนี้จะดำเนินต่อไปเมื่อเวลาผ่านไปว่า Swift เป็น ABI อย่างเป็นทางการและโมดูลมีเสถียรภาพเหมือน Swift 5.0 และ 5.1 ตามลำดับ
@objc