สวิฟท์ตัวเองไม่ได้ใช้ตัวเลือก - รูปแบบการออกแบบหลายอย่างที่ใน Objective-C ใช้ประโยชน์จากตัวเลือกทำงานแตกต่างกันในสวิฟท์ (ตัวอย่างเช่นใช้การผูกมัดตัวเลือกกับประเภทโปรโตคอลหรือis
/ as
ทดสอบแทนrespondsToSelector:
และใช้การปิดทุกที่ที่คุณสามารถทำได้แทนperformSelector:
เพื่อความปลอดภัยประเภท / หน่วยความจำที่ดีขึ้น)
แต่ยังมี API ที่ใช้ ObjC ที่สำคัญหลายตัวที่ใช้ตัวเลือกรวมถึงตัวจับเวลาและรูปแบบเป้าหมาย / การกระทำ Swift จัดเตรียมSelector
ประเภทสำหรับการทำงานกับสิ่งเหล่านี้ (Swift ใช้สิ่งนี้โดยอัตโนมัติแทนประเภทของ ObjC SEL
)
ใน Swift 2.2 (Xcode 7.3) และใหม่กว่า (รวมถึง Swift 3 / Xcode 8 และ Swift 4 / Xcode 9):
คุณสามารถสร้าง a Selector
จากฟังก์ชันประเภท Swift โดยใช้#selector
นิพจน์
let timer = Timer(timeInterval: 1, target: object,
selector: #selector(MyClass.test),
userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
with: button, with: otherButton)
สิ่งที่ดีเกี่ยวกับวิธีการนี การอ้างอิงฟังก์ชั่นถูกตรวจสอบโดยคอมไพเลอร์ Swift ดังนั้นคุณสามารถใช้#selector
นิพจน์กับคู่คลาส / วิธีที่มีอยู่จริงและมีสิทธิ์ใช้งานเป็นตัวเลือก (ดู "ความพร้อมใช้ของตัวเลือก" ด้านล่าง) คุณยังมีอิสระที่จะทำให้การอ้างอิงฟังก์ชั่นของคุณเท่านั้นที่เป็นเฉพาะที่คุณต้องการให้เป็นไปตามกฎระเบียบที่สวิฟท์ 2.2 ขึ้นไปสำหรับการทำงานประเภทการตั้งชื่อ
(นี่เป็นการปรับปรุง@selector()
คำสั่งของ ObjC เนื่องจากการ-Wundeclared-selector
ตรวจสอบคอมไพเลอร์ตรวจสอบเฉพาะว่าตัวเลือกที่มีชื่ออยู่แล้วการอ้างอิงฟังก์ชัน Swift ที่คุณส่งผ่านไปยังการ#selector
ตรวจสอบการมีอยู่เป็นสมาชิกในชั้นเรียนและประเภทลายเซ็น)
มีข้อควรระวังเพิ่มเติมสองสามประการสำหรับการอ้างอิงฟังก์ชันที่คุณส่งผ่านไปยัง#selector
นิพจน์:
- ฟังก์ชั่นหลายอย่างที่มีชื่อฐานเดียวกันสามารถสร้างความแตกต่างได้โดยใช้ชื่อพารามิเตอร์โดยใช้ไวยากรณ์ข้างต้นสำหรับการอ้างอิงฟังก์ชั่น (เช่น
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
) แต่ถ้าฟังก์ชั่นไม่มีพารามิเตอร์วิธีเดียวที่จะทำให้กระจ่างก็คือการใช้ตัวas
ละครที่มีลายเซ็นประเภทของฟังก์ชั่น (เช่นfoo as () -> ()
vs foo(_:)
)
- มีไวยากรณ์พิเศษสำหรับคู่คุณสมบัติ getter / setter ใน Swift 3.0+ ยกตัวอย่างเช่นที่กำหนด
var foo: Int
คุณสามารถใช้หรือ#selector(getter: MyClass.foo)
#selector(setter: MyClass.foo)
บันทึกทั่วไป:
กรณีที่#selector
ไม่ได้ผลและการตั้งชื่อ:บางครั้งคุณไม่มีการอ้างอิงฟังก์ชั่นเพื่อสร้างตัวเลือกด้วย (ตัวอย่างเช่นด้วยวิธีการที่ลงทะเบียนแบบไดนามิกใน ObjC runtime) ในกรณีนั้นคุณสามารถสร้าง a Selector
จากสตริง: เช่นSelector("dynamicMethod:")
- แม้ว่าคุณจะสูญเสียการตรวจสอบความถูกต้องของคอมไพเลอร์ เมื่อคุณทำเช่นนั้นคุณจะต้องปฏิบัติตามกฎการตั้งชื่อ ObjC รวมถึง colons ( :
) สำหรับแต่ละพารามิเตอร์
ความพร้อมใช้ของตัวเลือก:วิธีการอ้างอิงโดยตัวเลือกต้องเปิดเผยกับ ObjC runtime ใน Swift 4 ทุกวิธีที่เปิดเผยกับ ObjC จะต้องมีการประกาศ@objc
ล่วงหน้าด้วยแอตทริบิวต์ (ในเวอร์ชันก่อนหน้าคุณมีแอททริบิวต์นั้นฟรีในบางกรณี แต่ตอนนี้คุณต้องประกาศอย่างชัดเจน)
โปรดจำไว้ว่าprivate
สัญลักษณ์นั้นไม่ได้ปรากฏในรันไทม์เช่นกัน - วิธีการของคุณต้องมีinternal
การเปิดเผยอย่างน้อย
เส้นทางหลัก: สิ่งเหล่านี้เกี่ยวข้องกับ แต่ไม่เหมือนกับตัวเลือก มีไวยากรณ์พิเศษเหล่านี้อยู่ในสวิฟท์ 3 เกินไป: chris.valueForKeyPath(#keyPath(Person.friends.firstName))
เช่น ดูSE-0062สำหรับรายละเอียด และKeyPath
สิ่งอื่น ๆ อีกมากมายใน Swift 4ดังนั้นตรวจสอบให้แน่ใจว่าคุณใช้ API ที่ใช้ KeyPath ที่ถูกต้องแทนตัวเลือกตามความเหมาะสม
คุณสามารถอ่านเพิ่มเติมเกี่ยวกับตัวเลือกภายใต้การมีปฏิสัมพันธ์กับ APIs Objective-Cในการใช้สวิฟท์กับโกโก้และวัตถุประสงค์ -C
หมายเหตุ:ก่อน Swift 2.2 Selector
เป็นไปตามStringLiteralConvertible
ดังนั้นคุณอาจพบรหัสเก่าที่มีการส่งสตริงเปลือยไปยัง API ที่ใช้ตัวเลือก คุณจะต้องการที่จะเรียกใช้ "แปลงปัจจุบัน Swift ไวยากรณ์" ใน Xcode #selector
เพื่อให้ได้ผู้ที่ใช้
selector: test()
จะเรียกtest
และผ่านมันส่งกลับค่าให้กับการselector
โต้แย้ง