'#selector' หมายถึงวิธีการที่ไม่เปิดเผย Objective-C


105

Xcode 7.3 ใหม่ที่ส่งผ่านพารามิเตอร์ผ่าน addTarget มักจะใช้ได้กับฉัน แต่ในกรณีนี้มันทำให้เกิดข้อผิดพลาดในชื่อเรื่อง ความคิดใด ๆ ? มันพ่นอีกครั้งเมื่อฉันพยายามเปลี่ยนเป็น @objc

ขอบคุณ!

cell.commentButton.addTarget(self, action: #selector(FeedViewController.didTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

ตัวเลือกที่กำลังโทร

func didTapCommentButton(post: Post) {
}

3
บรรทัดการประกาศคลาสของ FeedViewController มีลักษณะอย่างไร? didTapCommentButton ประกาศอย่างไร? คุณได้รับข้อผิดพลาดอะไรเมื่อเพิ่ม @objc
vacawama

1
อัปเดตฉันแก้ไขโพสต์ของฉัน ตอนนี้ฉันอยู่ห่างจากคอมพิวเตอร์ที่เปิดอยู่ดังนั้นฉันจึงลืมข้อความแสดงข้อผิดพลาดที่แน่นอน แต่เป็นหนึ่งในสถานการณ์ที่ XCode บอกให้ฉันเพิ่มจากนั้นจึงเกิดข้อผิดพลาดในการตัดสินใจของตัวเอง
Echizzle

2
ชั้นเรียนของคุณประกาศ@objcหรือเป็นคลาสย่อยของNSObject?
NRitH

2
ลองลบวงเล็บออกได้ไหม เป็นเรื่องผิดปกติเมื่อพิจารณาว่าคุณไม่ควรเรียกใช้ฟังก์ชันในตัวเลือก
DanielEdrisian

สิ่งนี้ช่วยแก้ปัญหาของฉันได้ในไม่กี่
Darko

คำตอบ:


173

privateในกรณีของการทำงานของตัวเลือกเป็น เมื่อฉันลบprivateข้อผิดพลาดก็หายไป fileprivateเดียวกันจะไปสำหรับ

ใน Swift 4
คุณจะต้องเพิ่ม@objcการประกาศฟังก์ชัน จนกระทั่งเร็ว 4 สิ่งนี้ถูกอนุมานโดยปริยาย


2
fileprivateนอกจาก
hstdt

great catch @shaked
jbouaziz

@hstdt ดังนั้นถ้าคุณตั้งค่าfileprivateจะแก้ไขได้หรือไม่
Hemang

2
@Hemang ไม่มี @hstdt หมายความว่าค่าprivateมิได้fileprivateจะทำงาน
Gobe

การสร้าง func ด้วยไดนามิกนั้นเหมาะสมกว่าการลบ private / fileprivate
บุญ

57

คุณจำเป็นต้องใช้@objcแอตทริบิวต์ในที่จะใช้กับdidTapCommentButton(_:)#selector

คุณบอกว่าคุณทำอย่างนั้น แต่คุณได้รับข้อผิดพลาดอื่น ฉันเดาว่าข้อผิดพลาดใหม่Postไม่ใช่ประเภทที่เข้ากันได้กับ Objective-C คุณสามารถแสดงเมธอดต่อ Objective-C ได้ก็ต่อเมื่อประเภทอาร์กิวเมนต์ทั้งหมดและประเภทการส่งคืนเข้ากันได้กับ Objective-C

คุณสามารถแก้ไขได้โดยการสร้างPostคลาสย่อยของNSObjectแต่นั่นจะไม่สำคัญเพราะการโต้แย้งdidTapCommentButton(_:)จะไม่เป็นPostอย่างไรก็ตาม อาร์กิวเมนต์ของฟังก์ชันการดำเนินการคือผู้ส่งการดำเนินการและผู้ส่งจะเป็นcommentButtonซึ่งสันนิษฐานว่ากUIButton. คุณควรประกาศdidTapCommentButtonดังนี้:

@objc func didTapCommentButton(sender: UIButton) {
    // ...
}

จากนั้นคุณจะประสบปัญหาในการรับปุ่มที่Postตรงกัน มีหลายวิธีที่จะได้รับ นี่คือหนึ่ง

ฉันรวบรวม (เนื่องจากรหัสของคุณบอกcell.commentButton) ว่าคุณกำลังตั้งค่ามุมมองตาราง (หรือมุมมองคอลเลกชัน) และเนื่องจากเซลล์ของคุณมีคุณสมบัติที่ไม่ได้มาตรฐานcommentButtonฉันจึงถือว่าเป็นUITableViewCellคลาสย่อยที่กำหนดเอง สมมติว่าเซลล์ของคุณPostCellประกาศดังนี้:

class PostCell: UITableViewCell {
    @IBOutlet var commentButton: UIButton?
    var post: Post?

    // other stuff...
}

จากนั้นคุณสามารถเดินตามลำดับชั้นของมุมมองจากปุ่มเพื่อค้นหาPostCellและรับโพสต์จากมัน:

@objc func didTapCommentButton(sender: UIButton) {
    var ancestor = sender.superview
    while ancestor != nil && !(ancestor! is PostCell) {
        ancestor = view.superview
    }
    guard let cell = ancestor as? PostCell,
        post = cell.post
        else { return }

    // Do something with post here
}

หากฉันต้องการใช้กับฟังก์ชันส่วนกลาง? @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
TomSawyer

คุณไม่สามารถใช้กับฟังก์ชันส่วนกลางได้
rob mayoff

8

ลองให้ตัวเลือกชี้ไปที่ฟังก์ชัน wrapper ซึ่งจะเรียกใช้ฟังก์ชัน delegate ของคุณ ที่ได้ผลสำหรับฉัน

cell.commentButton.addTarget(self, action: #selector(wrapperForDidTapCommentButton(_:)), forControlEvents: UIControlEvents.TouchUpInside)

-

func wrapperForDidTapCommentButton(post: Post) {
     FeedViewController.didTapCommentButton(post)
}

1
ทำงานให้ฉัน! ยังไม่แน่ใจว่าทำไมถึงจำเป็น แต่จะเอาไป!
Paul Lehn

0

อย่างที่คุณselector[About]บอกว่าObjective-Cควรใช้รันไทม์ การประกาศที่มีการทำเครื่องหมายว่าเป็นprivateหรือfileprivateไม่ได้สัมผัสกับรันไทม์ Objective-C โดยค่าเริ่มต้น นั่นคือเหตุผลที่คุณมีสองรูปแบบ:

  1. ทำเครื่องหมายprivateหรือfileprivateประกาศโดย@objc[About]
  2. การใช้งานinternal, public, openปรับปรุงการเข้าถึง[เกี่ยวกับ]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.