'#selector' đề cập đến một phương pháp không tiếp xúc với Objective-C


105

Xcode 7.3 mới truyền tham số qua addTarget thường phù hợp với tôi nhưng trong trường hợp này, nó gây ra lỗi trong tiêu đề. Bất kỳ ý tưởng? Nó ném một cái khác khi tôi cố gắng thay đổi nó thành @objc

Cảm ơn bạn!

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

Bộ chọn nó đang gọi

func didTapCommentButton(post: Post) {
}

3
Dòng khai báo lớp của FeedViewController trông như thế nào? DidTapCommentButton được khai báo như thế nào? Bạn gặp lỗi gì khi thêm @objc?
vacawama

1
Cập nhật, tôi đã chỉnh sửa bài đăng của mình. Tôi đang ở xa máy tính, nó đang bật nên tôi quên thông báo lỗi chính xác nhưng đó là một trong những tình huống mà XCode yêu cầu tôi thêm nó sau đó tự xử lý lỗi.
Echizzle

2
Lớp của bạn có khai báo @objchay là một lớp con của NSObject?
NRitH

2
Bạn có thể thử loại bỏ dấu ngoặc đơn không? Thật bất thường khi bạn không nên gọi một hàm trong bộ chọn.
DanielEdrisian

Điều này đã giải quyết vấn đề của tôi trong http://stackoverflow.com/a/36963058/1685165
Darko

Câu trả lời:


173

Trong trường hợp của tôi, chức năng của bộ chọn là private. Sau khi tôi loại bỏ privatelỗi đã biến mất. Cũng vậy fileprivate.

Trong Swift 4
Bạn sẽ cần thêm @objcvào khai báo hàm. Cho đến nhanh 4 điều này đã được suy ra một cách ngầm.


2
Ngoài ra fileprivate.
hstdt

bắt tuyệt vời @shaked
jbouaziz

@hstdt, vậy nếu bạn đặt fileprivatethì có giải quyết được không?
Hemang

2
@Hemang, không, @hstdt có nghĩa là không privatevà cũng không fileprivatehoạt động
Gobe

Tạo func với động thích hợp hơn là xóa private / fileprivate.
Boon

57

Bạn cần sử dụng @objcthuộc tính on didTapCommentButton(_:)để sử dụng nó với #selector.

Bạn nói rằng bạn đã làm điều đó nhưng bạn lại gặp một lỗi khác. Tôi đoán là lỗi mới Postkhông phải là loại tương thích với Objective-C. Bạn chỉ có thể hiển thị một phương thức cho Objective-C nếu tất cả các loại đối số và kiểu trả về của nó tương thích với Objective-C.

Bạn có thể khắc phục điều đó bằng cách tạo Postmột lớp con của NSObject, nhưng điều đó sẽ không thành vấn đề, vì dù sao thì đối số didTapCommentButton(_:)sẽ không phải là một Post. Đối số của một hàm hành động là người gửi hành động và người gửi đó sẽ là commentButton, có lẽ là a UIButton. Bạn nên khai báo didTapCommentButtonnhư thế này:

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

Sau đó, bạn sẽ phải đối mặt với vấn đề nhận được Posttương ứng với nút được nhấn. Có nhiều cách để có được nó. Đây là một.

Tôi thu thập được (vì mã của bạn cho biết cell.commentButton) rằng bạn đang thiết lập chế độ xem bảng (hoặc chế độ xem bộ sưu tập). Và vì ô của bạn có thuộc tính không chuẩn có têncommentButton , tôi cho rằng đó là một UITableViewCelllớp con tùy chỉnh . Vì vậy, hãy giả sử ô của bạn được PostCellkhai báo như thế này:

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

    // other stuff...
}

Sau đó, bạn có thể đi lên hệ thống phân cấp chế độ xem từ nút để tìm PostCellvà lấy bài đăng từ đó:

@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
}

Nếu tôi muốn sử dụng nó với chức năng toàn cầu? @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
TomSawyer

Bạn không thể sử dụng nó với một chức năng toàn cục.
cướp mayoff

8

Thử đặt bộ chọn trỏ đến một hàm trình bao bọc, hàm này sẽ gọi hàm đại biểu của bạn. Điều đó đã làm việc cho tôi.

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

-

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

1
Đã làm cho tôi! vẫn không chắc tại sao điều này là cần thiết nhưng tôi sẽ lấy nó!
Paul Lehn,

0

Như bạn biết selector[Giới thiệu] nói rằng Objective-Cthời gian chạy nên được sử dụng. Các khai báo được đánh dấu là privatehoặc fileprivatekhông được hiển thị trong thời gian chạy Objective-C theo mặc định . Đó là lý do tại sao bạn có hai biến thể:

  1. Đánh dấu privatehoặc fileprivatetuyên bố của bạn bằng @objc[Giới thiệu]
  2. Sử dụng internal, public, opentruy cập modifier [Về]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.