เมื่อใดควรใช้ @objc ใน Swift


90

ใน Swift ฉันเห็นวิธีการบางอย่างเช่น:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

ฉันสงสัยว่าเมื่อใดควรใช้ @objc? ฉันอ่านเอกสารบางฉบับ แต่พวกเขากำลังบอกว่าเมื่อคุณต้องการให้เรียกได้ใน Objective-C คุณควรเพิ่มแฟล็ก @objc

อย่างไรก็ตามนี่เป็นฟังก์ชั่นส่วนตัวใน Swift @obj ทำอะไร?


1
คำถามดี !!!
Erhan Demirci

คำตอบ:


69

ความหมายส่วนตัวมองเห็นได้เฉพาะใน Swift ดังนั้นใช้ @objc เพื่อให้มองเห็นได้ใน Objective-C หากคุณมี func เพื่อเลือก func ส่วนตัวอย่างรวดเร็วจำเป็นต้องมี

แอตทริบิวต์ @objc ทำให้ Swift API ของคุณพร้อมใช้งานใน Objective-C และรันไทม์ Objective-C

ดู: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html


1
เพื่อให้@objc private func doubleTapGestureRecognizedสิ่งที่เป็นจุดที่จะมีทั้ง @objc และเอกชน? คุณกำลังบอกว่าคลาส Objective-C สามารถเขียนทับ doubleTapGestureRecognized ได้หรือไม่?
Wingzero

1
ฉันเดาว่าเพราะใน obj-c คุณสามารถเขียนทับวิธีการใดก็ได้
แปลกประหลาด

2
ไม่แน่ใจว่าคำตอบนี้ถูกต้องอย่างไร & ตอบคำถามของเขา ans ที่ให้ไว้ที่นี่มีอยู่แล้วใน Q ของเขาเอง "แต่พวกเขาบอกว่าเมื่อคุณต้องการให้สามารถเรียกได้ใน Objective-C คุณควรเพิ่ม \ @objc flag" ซึ่งเป็นหลักของเขา คำถามคือ "นี่เป็นฟังก์ชันส่วนตัวที่รวดเร็ว \ @obj ทำอะไร"
KBJ

3
ลิงค์แตก โดยเฉพาะอย่างยิ่งในเอกสารของ Apple โปรดพิจารณาแยกองค์ประกอบสำคัญจากเอกสารประกอบที่นี่
levigroker

57

อีกคำตอบที่ล่าช้า แต่ไม่มีคำตอบใดที่มีอยู่ในคำถามนี้ที่ตอบคำถามของ OP ได้จริงนั่นคือ: ทำไมคุณถึงต้องใช้@objcกับprivateสมาชิกชั้นเรียนถ้า@objcมีเพื่อโต้ตอบกับ Objective-C และสมาชิกที่มีปัญหา เป็นแบบส่วนตัวหมายความว่าแม้ว่าคุณจะมีรหัส Objective-C ในโปรเจ็กต์ของคุณ แต่ก็ไม่ควรมองเห็นสมาชิกได้ใช่ไหม

เหตุผลก็คือเนื่องจากเฟรมเวิร์กจำนวนมากถูกเขียนใน Objective-C บางครั้งคุณสมบัติของ Objective-C จึงจำเป็นสำหรับการโต้ตอบกับ API บางตัว

ตัวอย่างเช่นสมมติว่าฉันต้องการลงทะเบียนเพื่อรับการแจ้งเตือนผ่านDistributedNotificationCenter:

DistributedNotificationCenter.default.addObserver(self,
                                                  selector: #selector(somethingHappened(_:)),
                                                  name: someNotification,
                                                  object: nil)

เพื่อให้ได้ผลเราต้องสามารถรับตัวเลือกสำหรับsomethingHappenedวิธีการได้ อย่างไรก็ตามตัวเลือกเป็นแนวคิดของ Objective-C ดังนั้นหาก Objective-C มองไม่เห็นเมธอดแสดงว่าไม่มีตัวเลือก ดังนั้นแม้ว่าเมธอดจะเป็นแบบส่วนตัวและไม่ควรถูกเรียกโดยใช้รหัสภายนอกโดยพลการ แต่ก็จำเป็นต้องมี@objcคำสั่งเพื่อให้DistributedNotificationโค้ดซึ่งเขียนด้วย Objective-C สามารถเรียกใช้ผ่านตัวเลือกได้

อีกกรณีหนึ่งที่@objcจำเป็นคือการรองรับ Key-Value Coding (KVC) โดยเฉพาะอย่างยิ่งบน macOS ที่ใช้ KVC และ KVO เพื่อใช้งาน Cocoa Bindings KVC ก็เหมือนกับระบบอื่น ๆ ใน Cocoa ที่ใช้ใน Objective-C ซึ่งมีผลทำให้คุณสมบัติที่สอดคล้องกับ KVC ต้องสัมผัสกับรันไทม์ Objective-C ในบางครั้งคุณสมบัติที่สอดคล้องกับ KVC เป็นเรื่องส่วนตัว ตัวอย่างหนึ่งคือเมื่อคุณมีคุณสมบัติที่ส่งผลต่อคุณสมบัติอื่น ๆ :

@objc private dynamic var originalProperty: String

@objc private static let keyPathsForValuesAffectingDependentProperty: Set<String> = [
    #keyPath(originalProperty)
]
@objc public var dependentProperty: String { return changeItSomehow(self.originalProperty) }

ในกรณีนี้ทรัพย์สินที่เก็บไว้ของเราที่เกิดขึ้นจริงเป็นส่วนตัว แต่ขึ้นอยู่กับสถานที่ให้บริการซึ่งเราไม่เปิดเผยรหัสข้างนอกต้องส่งการแจ้งเตือนเมื่อทรัพย์สินส่วนตัวที่มีการปรับปรุง การทำเครื่องหมายทรัพย์สินส่วนตัวเป็น@objcเราสามารถทำได้อย่างง่ายดายโดยตั้งค่าการอ้างอิง KVC มิฉะนั้นเราจะต้องเขียนโค้ดเพื่อส่งการแจ้งเตือนด้วยตนเองในทรัพย์สินส่วนตัวwillSetและdidSetตัวจัดการ นอกจากนี้คุณสมบัติคงที่ที่แจ้งระบบ KVC ที่dependentPropertyขึ้นอยู่กับoriginalPropertyความต้องการที่จะเปิดเผยกับ Objective-C เพื่อให้ระบบ KVC ค้นหาและเรียกมัน แต่ไม่เกี่ยวข้องกับไคลเอนต์ของรหัสของเรา

นอกจากนี้ตัวควบคุมมุมมองในแอพ macOS ที่อัปเดตการควบคุมในมุมมองโดยใช้ Cocoa Bindings เป็นรายละเอียดการใช้งานอาจทำให้คุณสมบัติส่วนตัวบางอย่างสอดคล้องกับ KVC เพื่อผูกการควบคุมเหล่านั้นเข้ากับพวกเขา

ดังที่คุณเห็นมีหลายครั้งที่อาจต้องเปิดเผยเมธอดหรือคุณสมบัติกับ Objective-C เพื่อโต้ตอบกับเฟรมเวิร์กโดยไม่จำเป็นต้องให้ลูกค้ามองเห็นโค้ดของคุณ


ขอบคุณ. นี่เป็นคำตอบที่ดีที่ตอบคำถามโดยตรง
hqt

25

@objc / ไดนามิก

สำหรับความเข้ากันได้: เมื่อคุณนำเข้าไฟล์ / รหัส Swift ของคุณไปยังโครงการที่ใช้ Objective-C

และใช้สิ่งนั้นหากคุณต้องการให้คุณสมบัติ / วิธีการของคุณถูกเข้าถึงโดยรหัส Objective-C หรือคลาส

เวลาส่วนใหญ่จะเกิดขึ้นเมื่อคุณย่อยคลาส Swift ของคลาสพื้นฐาน Objective-C

คลาส Swift หรือโปรโตคอลต้องทำเครื่องหมายด้วยแอตทริบิวต์@objcเพื่อให้สามารถเข้าถึงและใช้งานได้ใน Objective-C แอตทริบิวต์นี้บอกคอมไพเลอร์ว่าโค้ด Swift ส่วนนี้สามารถเข้าถึงได้จาก Objective-C หากคลาส Swift ของคุณเป็นลูกหลานของคลาส Objective-C คอมไพเลอร์จะเพิ่มแอตทริบิวต์ @objc ให้คุณโดยอัตโนมัติ

@objcนี่เอกสารแอปเปิ้ลที่บอกว่าเกี่ยวกับ

ใช้ Swift จาก Objective-C

ความเข้ากันได้ของการทำงานร่วมกันของภาษา

ลิงก์อัปเดต:
ดูเหมือนว่าลิงก์ได้รับการอัปเดตโดย apple


11

@objc เป็นแอตทริบิวต์คลาสดังนั้นคุณจึงใช้

@objc public class MyClass

มันแสดงวิธีการของคลาสไปยังคลาส Objective C ดังนั้นคุณจะใช้ได้ก็ต่อเมื่อคลาสของคุณมีฟังก์ชันสาธารณะ


8

คำตอบที่ล่าช้า แต่@objcพฤติกรรมนี้เปลี่ยนไปเล็กน้อยเมื่อเทียบกับ Swift 4 (ซึ่งออกมาใน Xcode 9 ซึ่งโดยทั่วไปเผยแพร่เมื่อ 10 วันที่แล้ว)

ใน Swift 4 กรณีการอนุมานบางส่วน@objcจะถูกลบออก นี่หมายถึงในบางกรณีเพิ่มเติมที่ก่อนที่@objcส่วนหัวจะถูกอนุมานโดยคอมไพเลอร์ Swift มันอยู่ใน Swift 4 ไม่ได้อนุมาน

อ่านเพิ่มเติมได้ที่ข้อเสนอวิวัฒนาการของ Swift เกี่ยวกับการเปลี่ยนแปลงนี้

ดังที่ได้กล่าวไปแล้วโดยทั่วไป@objcคือการเปิดเผยวิธีการบางอย่างกับรันไทม์ Objective-C ซึ่งเป็นส่วนหนึ่งของความสามารถในการทำงานร่วมกันของ Swift ในภาษา


1
นี่น่าจะเป็นเหตุผลว่าทำไมหลังจากอัปเดตเป็น Swift 4 แล้วตัวแปรบางตัวไม่สามารถเข้าถึงได้จาก ObjC ใช่ไหม? ด้วย Swift 3.X ไม่จำเป็นต้องเพิ่ม@objc
rgkobashi

โอเคการตรวจสอบกับคนอื่นเป็นเรื่องดีเสมอขอบคุณ
rgkobashi

1

@objcObjective-C runtimeหมายความว่าการประกาศให้เป็น มาดู#selectorคุณสมบัติของ Swift ในการใช้รันไทม์ Objective-C ในกรณีนี้คุณสามารถกำหนด Swift @objc private func[เพิ่มเติม] ของคุณได้

ในการใช้ฟังก์ชันของ Swift จาก Objective-C:

  1. ชั้นเรียนของ Swift ควรขยายจาก NSObject
  2. Mark Swift's:

    ก. @objcMembers ระดับเท่านั้น - ที่จะเปิดเผยทุก public ก่อสร้าง , เขตและวิธีการ นอกจากนี้ยังสามารถใช้ได้กับคลาสย่อย

    ข. @objc class / enum / protocol (ยกเว้นstruct ) [Named Type]

    • @objc ระดับ (อุปกรณ์เสริม) - จะเปิดเผยค่าเริ่มต้น public init()หรือ@objc(<custom_name>)ตั้งชื่อที่กำหนดเองสำหรับคลาส
    • @objc ก่อสร้าง , เขตและวิธีการ - เพื่อให้พวกเขาเลือกที่

วิธีการของ Swift จะสามารถใช้ได้ในการตั้งชื่อครั้งต่อไป:

<swiftName>With<firstArgument>:<secondArgument>:

ตัวอย่างเช่น:

public func printHelloWorld(arg1: String, arg2:String)
//is reached through: 
[someObject printHelloWorldWithArg1: arg2:];

[ @objcและdynamic]

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