Khi nào sử dụng @objc trong Swift?


87

Trong Swift, tôi thấy một số phương thức như:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

Tôi đã tự hỏi, khi nào thì sử dụng @objc? Tôi đã đọc một số tài liệu, nhưng họ nói rằng khi bạn muốn nó có thể gọi được trong Objective-C, bạn nên thêm cờ @objc

Tuy nhiên, đây là một chức năng riêng tư trong Swift, @obj làm gì?


1
câu hỏi hay !!!
Erhan Demirci

Câu trả lời:


67

riêng tư nghĩa là nó chỉ hiển thị trong Swift. vì vậy hãy sử dụng @objc để hiển thị trong Objective-C. Nếu bạn có một func để chọn một func riêng nhanh chóng, thì nó là bắt buộc.

Thuộc tính @objc làm cho API Swift của bạn có sẵn trong Objective-C và Objective-C runtime.

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

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


1
vì vậy @objc private func doubleTapGestureRecognized, có ích gì khi có cả @objc và private? Bạn đang nói các lớp Objective-C có thể ghi đè lên doubleTapGestureRecognized?
Wingzero

1
Tôi đoán, bởi vì trong obj-c, bạn có thể ghi đè bất kỳ phương thức nào.
kỳ lạ vào

2
Không chắc câu trả lời này đúng như thế nào & trả lời câu Q. của anh ấy. Các ans được cung cấp ở đây đã nằm trong chính Q của anh ấy "nhưng họ nói khi bạn muốn nó có thể gọi được trong Objective-C, bạn nên thêm \ @objc flag", chính Câu hỏi là "Đây là một chức năng riêng tư nhanh chóng, \ @obj làm gì?"
KBJ

3
Liên kết đứt đoạn. Đặc biệt là vào tài liệu của Apple. Vui lòng xem xét trích xuất các yếu tố chính từ tài liệu ở đây.
levigroker

55

Một câu trả lời muộn khác, nhưng không có câu trả lời hiện có nào cho câu hỏi này thực sự trả lời câu hỏi của OP, đó là: tại sao bạn lại cần sử dụng cái quái gì cho @objcmột privatethành viên trong lớp, nếu @objccó để tương tác với Objective-C và thành viên được đề cập. là riêng tư, có nghĩa là ngay cả khi bạn có mã Objective-C trong dự án của mình, nó vẫn không thể nhìn thấy thành viên?

Lý do là vì nhiều khuôn khổ được viết bằng Objective-C, đôi khi các tính năng Objective-C là cần thiết để tương tác với một số API nhất định.

Ví dụ: giả sử tôi muốn đăng ký nhận thông báo qua DistributedNotificationCenter:

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

Để điều này hoạt động, chúng ta cần có bộ chọn cho somethingHappenedphương thức. Tuy nhiên, bộ chọn là một khái niệm Objective-C, vì vậy nếu phương thức không hiển thị với Objective-C, nó không có bộ chọn. Do đó, ngay cả khi phương thức là private và không nên được gọi bằng mã bên ngoài tùy ý, nó sẽ cần một @objcthứ tự cho DistributedNotificationmã, được viết bằng Objective-C, để có thể gọi nó thông qua bộ chọn của nó.

Một trường hợp phổ biến khác @objccần thiết là hỗ trợ Mã hóa khóa-giá trị (KVC), đặc biệt là trên macOS, nơi KVC và KVO được sử dụng để triển khai Liên kết ca cao. KVC, giống như nhiều hệ thống khác trong Cacao, được triển khai trong Objective-C, có tác dụng yêu cầu các thuộc tính tuân thủ KVC được hiển thị trong thời gian chạy Objective-C. Đôi khi, các thuộc tính tuân thủ KVC là riêng tư. Một ví dụ là khi bạn có một thuộc tính ảnh hưởng đến các thuộc tính khác:

@objc private dynamic var originalProperty: String

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

Trong trường hợp này, thuộc tính được lưu trữ thực tế của chúng tôi là riêng tư, nhưng thuộc tính phụ thuộc mà chúng tôi để lộ ra bên ngoài mã cần gửi thông báo khi thuộc tính riêng được cập nhật. Bằng cách đánh dấu thuộc tính riêng là @objc, chúng tôi có thể dễ dàng thực hiện điều đó bằng cách thiết lập phụ thuộc KVC — nếu không, chúng tôi sẽ phải viết mã để gửi thủ công các thông báo trong thuộc tính riêng willSetdidSettrình xử lý. Ngoài ra, thuộc tính tĩnh thông báo cho hệ thống KVC dependentPropertyphụ thuộc vào originalPropertycần được tiếp xúc với Objective-C để hệ thống KVC tìm thấy nó và gọi nó, nhưng nó không liên quan đến các máy khách của mã của chúng tôi.

Ngoài ra, bộ điều khiển chế độ xem trong ứng dụng macOS cập nhật các điều khiển trong chế độ xem của nó bằng cách sử dụng Cocoa Bindings làm chi tiết triển khai có thể làm cho các thuộc tính riêng tư nhất định tuân thủ KVC để ràng buộc các điều khiển đó với chúng.

Vì vậy, như bạn thấy, đôi khi một phương thức hoặc thuộc tính có thể cần được tiếp xúc với Objective-C để tương tác với các khung công tác, mà không nhất thiết phải hiển thị cho khách hàng sử dụng mã của bạn.


25

@objc / dynamic

Nó để tương thích: Sau khi bạn nhập tệp / mã Swift của mình vào dự án dựa trên Objective-C.

Và sử dụng nó nếu bạn muốn thuộc tính / phương thức của mình được truy cập bằng mã hoặc lớp Objective-C.

Hầu hết thời gian nó xảy ra khi bạn đang phân lớp một lớp Swift của lớp cơ sở Objective-C.

Một lớp hoặc giao thức Swift phải được đánh dấu bằng thuộc tính @objc để có thể truy cập và sử dụng được trong Objective-C. Thuộc tính này cho trình biên dịch biết rằng đoạn mã Swift này có thể được truy cập từ Objective-C. Nếu lớp Swift của bạn là con của lớp Objective-C, trình biên dịch sẽ tự động thêm thuộc tính @objc cho bạn.

Đây là tài liệu apple nói về @objc.

Sử dụng Swift từ Objective-C

Khả năng tương tác Ngôn ngữ Tương thích

Liên kết được cập nhật:
Có vẻ như các liên kết đã được Apple cập nhật.


11

@objc là một thuộc tính lớp, vì vậy bạn sử dụng

@objc public class MyClass

Nó hiển thị các phương thức của lớp cho các lớp Objective C, vì vậy bạn sẽ chỉ sử dụng nó nếu lớp của bạn chứa các hàm công khai


7

Một câu trả lời muộn, nhưng @objchành vi này đang thay đổi một chút kể từ Swift 4 (xuất hiện trong Xcode 9, thường được phát hành 10 ngày trước).

Trong Swift 4, một số trường hợp suy luận @objcbị loại bỏ. Điều này chỉ có nghĩa là trong một số trường hợp bổ sung mà trước khi @objctiêu đề được trình biên dịch Swift suy ra, nó trong Swift 4 không được suy ra.

Đọc thêm tại đề xuất phát triển Swift về thay đổi này

Như đã được đề cập, nói chung @objclà để hiển thị các phương thức nhất định cho thời gian chạy Objective-C, là một phần của khả năng tương tác của Swift với ngôn ngữ.


1
vì vậy đây sẽ là lý do tại sao sau khi cập nhật lên Swift 4 một số biến không thể truy cập được từ ObjC phải không? Với Swift 3.x đã có không cần phải thêm@objc
rgkobashi

oh ok, luôn luôn tốt để kiểm tra lại với người khác, cảm ơn!
rgkobashi

1

@objcđể lộ ra một khai báo Objective-C runtime. Chúng ta hãy xem xét #selectortính năng của Swift để sử dụng thời gian chạy Objective-C. Trong trường hợp này, bạn có thể xác định Swift của mình @objc private func[Thêm]

Để sử dụng các chức năng của Swift từ Objective-C:

  1. Lớp học của Swift nên được mở rộng từ NSObject
  2. Đánh dấu Swift's:

    a. chỉ @objcMembers lớp - để hiển thị tất cả các hàm public tạo , trườngphương thức . Ngoài ra, nó có thể áp dụng cho các lớp con

    b. @objc class / enum / protocol (ngoại trừ struct ) [Loại được đặt tên]

    • @objc lớp (tùy chọn) - để hiển thị một mặc định public init() . Hoặc @objc(<custom_name>)để thiết lập một tên tùy chỉnh cho lớp.
    • @objc hàm tạo , trườngphương thức - để hiển thị chúng một cách có chọn lọc

Phương thức của Swift sẽ có sẵn bằng cách đặt tên tiếp theo:

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

Ví dụ:

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

[ @objcdynamic]

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.