Nhập giao thức Swift trong lớp Objective-C


116

Tôi cố gắng nhập một Giao thức Swift có tên AnalyticProtocolvào một lớp Objective-C có tên AnalyticFactory.

protocol AnalyticProtocol
{

}

Tôi đang bắt đầu từ một dự án Objective-C hiện có (tôi không tạo một dự án Swift mới với xCode và tôi không tìm thấy cách cấu hình dự án Objective-C của mình thành một dự án Swift trong xCode 6 ).

Trong tệp Swift của tôi, tôi đã bao gồm .htệp có tên MyProjectName-Swift.hnhưng trình biên dịch trả lại cho tôi một lỗi cho tôi biết rằng nó không tồn tại . Vì vậy, tôi đã tạo một .htệp có tên MyProjectName-Swift.hthực sự trống (tôi không biết mình nên đặt gì bên trong).

Trong tài liệu của Apple, họ nói rằng tôi phải đưa .htệp của mình có tên MyProjectName-Swift.hvào .mtệp của mình . Nhưng tôi cần đưa nó không phải vào .mtệp của tôi mà vào của tôi .h. Điều này có thể là vấn đề?

Khi tôi cố gắng biên dịch, tôi đã gặp lỗi này :: 0: error: xxxAnalyticFactory.h: 39: không thể tìm thấy khai báo giao thức cho 'AnalyticProtocol'

Và mã bao gồm:

@interface AnalyticFactory : NSObject
{
    Class<AnalyticProtocol> _analyticProtocolClass; // The type of the analytic class currently used.
}

Tôi nghĩ rằng tôi không hiểu rõ làm thế nào tôi có thể nhập một giao thức Swift vào một lớp Objective-C.

Có ai thấy lỗi trong việc tôi đang làm không?


Xem video Tích hợp Swift với Objective-C từ WWDC 2014. Vào khoảng 30:40 trong video, họ mô tả cách truy cập các giao thức Swift trong các lớp Objective-C.
Jamie Forrest

Câu trả lời:


224

Bạn cần thêm @objcthuộc tính vào giao thức Swift của mình như sau:

@objc protocol AnalyticProtocol {

}

25
Cảm ơn câu trả lời của bạn nhưng sự cố vẫn còn.
Jean Lebrument

Bạn có thể đăng một dự án mẫu tái tạo vấn đề không?
Jamie Forrest

Thêm @objc giúp tôi với nhập khẩu các lớp Swift để obj-C
SERG

19
@objc không phải lúc nào cũng hoạt động. Khi tuân theo một giao thức, đôi khi nó không hoạt động khi thêm giao thức vào tệp @interfacetrong .htệp. tuy nhiên, bạn có thể thêm giao thức vào chế độ riêng tư @interfacetrong .mtệp và nó sửa chữa mọi thứ (ít nhất là nó có cho tôi đôi khi). Vì vậy, trên @implementationcó của bạn @interface MyController() <AnalyticProtocol>.
Adam

1
Đôi khi Xcode 8 sẽ phàn nàn khi bạn đang chỉnh sửa, nhưng khi bạn thực sự xây dựng nó, làm theo câu trả lời này cùng với nhận xét, lỗi sẽ biến mất.
Roger Pingleton

77

Không thể nhập tiêu đề Swift được tạo Xcode trong tệp tiêu đề objC.

Vì vậy, vì bạn muốn sử dụng mã Swift trong tệp tiêu đề objC, bạn sẽ cần "khai báo chuyển tiếp" các lớp và giao thức bạn muốn sử dụng trong tệp tiêu đề objC, như sau:

@protocol AnalyticProtocol;

Bây giờ bạn có thể sử dụng giao thức trong khai báo lớp objC của mình:

@interface AnalyticFactory : NSObject
{
    Class<AnalyticProtocol> _analyticProtocolClass; // The type of the analytic class currently used.
}

Trong tệp triển khai của bạn (tệp objC .m), bạn có thể nhập tệp tiêu đề Swift được tạo bằng Xcode ("ProductModuleName-Swift.h") và việc triển khai chính xác AnalyticProtocolgiờ sẽ được trình biên dịch biết.

Điều này cũng được mô tả trong phần "Sử dụng Swift từ Objective-C" trong Apple Docs

Lưu ý rằng XCode sẽ đưa ra cảnh báo trong tệp tiêu đề objC khi bạn sử dụng giao thức được khai báo phía trước ("Không thể tìm thấy định nghĩa giao thức cho 'AnalyticProtocol'), nhưng điều này có thể bị bỏ qua - việc triển khai sẽ được tìm thấy tại thời điểm biên dịch.


19
Tại sao Xcode lại hiển thị cảnh báo thiếu giao thức khi nó biên dịch và hoạt động tốt? Bất kỳ cách nào để loại bỏ cảnh báo?
Oren

Tuy nhiên, vẫn không thể gọi các phương thức giao thức trên lớp này. Nó sẽ đưa ra lỗiNo visible @interface for <ClassName> declares the selector <protocolMethodName>
Elsa

nó tạo ra cảnh báo sau: "Không thể tìm thấy định nghĩa giao thức cho xxxx"
JAHelia

51

Đối với bất kỳ ai chỉ cần áp dụng một giao thức - bạn có thể thực hiện việc này theo hai bước mà không tạo ra bất kỳ cảnh báo hoặc lỗi nào:

  1. Trong .swifttệp của bạn , hãy thêm vào @objctrước tên giao thức:

    @objc protocol AnalyticProtocol {
    
    }
  2. Trong .mtệp của bạn , hãy nhập tiêu đề Swift đã tạo và áp dụng giao thức trong một danh mục riêng tư. (Tệp tiêu đề được đặt tên tự động):

    #import "ProductModuleName-Swift.h"
    
    @interface AnalyticFactory () <AnalyticProtocol>
    
    @end

Đây là cách tiếp cận được khuyến nghị của Apple. Bạn có thể tìm hiểu thêm về cách trộn và đối sánh Objective-C và Swift tại đây: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html


1
Tôi vẫn nhận được cảnh báo, có khai báo trước hoặc không. Tôi đang sử dụng giao thức trong một tiện ích mở rộng.
Cristi Băluță

Không thể nhập #import "AnalyticProtocol-Swift.h". Có vẻ như AnythingProtocol-Swift.h không được tạo tự động như bạn đã nói.
Hlung

2
Điều này đã làm việc cho tôi; không có đề xuất hoặc câu trả lời nào khác trên trang này hoạt động. Tôi đang trên Swift 4.
Poulsbo

1
Đây là cách duy nhất để loại bỏ các cảnh báo (mặc dù nó hoạt động khi các giao thức là trong file header)
David P

1
Các liên kết cùng có sẵn qua WebArchive: web.archive.org/web/20170310053717/https://developer.apple.com/...
Richard Topchii

3

Nếu bạn đang tạo một khuôn khổ, thì việc nhập bắt buộc

#import "ProductModuleName-Swift.h"

thay đổi:

#import <ProductModuleName/ProductModuleName-Swift.h>

Trong trường hợp này, bạn cũng phải đặt giao thức nhanh chóng ở chế độ công khai :

@objc public protocol AnalyticProtocol {
  func something();
}

3

Chúng ta có thể sử dụng các giao thức nhanh chóng trong Objective C với một vài thay đổi đối với mã. Ngoài ra, các giao thức được khai báo @objc cho phép bạn có các phương thức tùy chọn và bắt buộc mà không cần triển khai mặc định. Nó đi kèm với ưu và nhược điểm.

Chúng tôi thực sự có thể đổi tên giao thức thành tên mô tả hơn khi sử dụng trong Objective C. Tôi sử dụng "@objc (alias_name)".

Đây là mã, Hãy có một giao thức nhanh với thuộc tính @objc và tên bí danh để sử dụng trong mã ObjC.

@objc(ObjTableViewReloadable) protocol TableViewReloadable: class {
   func reloadRow(at index: IndexPath)
   func reloadSection(at index: Int)
   func reloadTable()
}

Bây giờ, hãy để trò chơi ô tô khai báo giao thức của chúng tôi trong tệp .h

@protocol ObjTableViewReloadable;

Bây giờ bạn có thể tuân theo giao thức này trong tệp .m và thêm triển khai các phương pháp bắt buộc.

#import "MyApp-Swift.h"
@interface MyObjcViewController () <ObjTableViewReloadable>

Cảm ơn vì đã đăng tải điều này. Tôi đang xem mã cũ hơn cũ hơn và nếu phương pháp này hoạt động, nó sẽ giúp tôi đỡ đau đớn. :)
Adrian
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.