[英]Throwing method cannot be an implementation of an @objc requirement because it returns a value of type `Bool`
I have IKabaSDK.h
which is a (Objective-C) protocol:我有
IKabaSDK.h
,它是一个 (Objective-C) 协议:
@import Foundation;
@import MobileSdk;
NS_ASSUME_NONNULL_BEGIN
@protocol IKabaSDK <NSObject>
- (BOOL)isStarted:(NSError* _Nullable __autoreleasing * _Nullable)error
__attribute__((swift_error(nonnull_error)))
NS_SWIFT_NAME(isStarted());
I have a (Swift) class KabaSDKThunk
where the said protocol is implemented:我有一个 (Swift) class
KabaSDKThunk
,其中实现了上述协议:
class KabaSDKThunk: NSObject, IKabaSDK {
func isStarted() throws -> Bool {
do {
try sdk.isStarted()
print("thunk getIsStarted")
} catch {
print("thunk getIsStarted throws \(error)")
throw error
}
}
...
}
Xcode gives me these two errors next to my implementation: Xcode 在我的实施旁边给了我这两个错误:
- Non-
@objc
methodisStarted()
does not satisfy requirement of@objc
protocolIKabaSDK
非
@objc
方法isStarted()
不满足@objc
协议IKabaSDK
的要求- Throwing method cannot be an implementation of an @objc requirement because it returns a value of type
Bool
;Throwing 方法不能是 @objc 要求的实现,因为它返回
Bool
类型的值; returnVoid
or a type that bridges to an Objective-C class返回
Void
或桥接到 Objective-C class 的类型
And If I don't add Bool
it complains that KabaSDKThunk
does not conform to protocol IKabaSDK
and suggests to add the Bool
return type, so the errors are mutually exclusive.如果我不添加
Bool
它会抱怨KabaSDKThunk
不符合协议IKabaSDK
并建议添加Bool
返回类型,因此错误是相互排斥的。 How do I solve the issue and why do we need Bool
and throw
here?我该如何解决这个问题,为什么我们需要
Bool
和throw
在这里?
why do we need
Bool
andthrow
为什么我们需要
Bool
和throw
This question boils down to what you in fact want to achieve.这个问题归结为您实际上想要实现的目标。 I agree the given behaviour is inconsistent, and moreover, the Swift bridging rules were changed in the past and is likely a subject to change in future, so what you have currently broken, can turn into working sample in foreseeable future.
我同意给定的行为是不一致的,此外,Swift 桥接规则在过去发生了变化,将来可能会发生变化,因此您目前所破坏的,可以在可预见的未来变成工作样本。 However for now, this error says it all:
但是现在,这个错误说明了一切:
Throwing method cannot be an implementation of an @objc requirement because it returns a value of type
Bool
;Throwing 方法不能是 @objc 要求的实现,因为它返回
Bool
类型的值; returnVoid
or a type that bridges to an Objective-C class返回
Void
或桥接到 Objective-C class 的类型
In other words, if your Swift method is marked with throws
keyword (and exposed to Objective-C runtime), it has to return a plain Objective-C type (not magically bridged Swift structures, like Int
, Bool
, Double
, etc.. it has to be something subclassed from NSObject
, NSProxy
or other Objective-C entities) OR return nothing.换句话说,如果您的 Swift 方法标有
throws
关键字(并暴露给 Objective-C 运行时),它必须返回一个普通的 Objective-C 类型(不是神奇地桥接 Swift 结构,如Int
、 Bool
、 Double
等。它必须是NSObject
、 NSProxy
或其他 Objective-C 实体的子类)或不返回任何内容。 Period.时期。 Take it as a rule (at least for now).
把它作为一个规则(至少现在)。 ( PS This specific situation indeed looks like an LLVM bug, because the same set of requirements works perfectly fine when applied to a non-protocol Objective-C method (submitted it here , so the community has a chance to review it))
( PS这种特定情况确实看起来像一个 LLVM 错误,因为相同的一组要求在应用于非协议 Objective-C 方法时工作得很好(在此处提交,因此社区有机会审查它))
Having that said, the proper workaround to this situation depends on your final goal.话虽如此,这种情况的正确解决方法取决于您的最终目标。
By "conventional" here I mean a contract that Cocoa/Cocoa touch programmer would usually expect.这里的“常规”是指 Cocoa/Cocoa touch 程序员通常期望的合同。 In this scenario a method with the following signature:
在这种情况下,具有以下签名的方法:
- (BOOL)failableMethodWithError:(NSError **)error;
Is commonly meant to fail wherever it returns NO
value (in the world of Objective-C).通常意味着在返回
NO
值的任何地方失败(在 Objective-C 的世界中)。 It's uncommon for Swift to deal with indirect parameters like NSError **
so in order to keep it consistent such methods are bridged as follows: Swift 处理像
NSError **
这样的间接参数并不常见,所以为了保持一致,这些方法桥接如下:
func failableMethod() throws
You can read more about this convention in the About Imported Cocoa Error Parameters documentation .您可以在关于导入的 Cocoa 错误参数文档中阅读有关此约定的更多信息。
swift_error(nonnull_error)
attributeswift_error(nonnull_error)
属性的保留返回类型的失败方法If you want to preserve return type AND the failable signature, you have two options.如果您想保留返回类型和可失败签名,您有两个选择。 First is by giving the method
swift_error(nonnull_error)
attribute.首先是给方法
swift_error(nonnull_error)
属性。 However in this case, in order to comply with existing bridging rules, your method has to have a type that "bridges" to an Objective-C class, eg NSNumber *
:但是在这种情况下,为了遵守现有的桥接规则,您的方法必须具有“桥接”到 Objective-C class 的类型,例如
NSNumber *
:
- (NSNumber *)failableMethodWithError:(NSError ** _Nullable)error __attribute__((swift_error(nonnull_error)));
And here is how you implement such a method in Swift:以下是如何在 Swift 中实现这种方法:
func failableMethod() throws -> NSNumber {
return NSNumber(booleanLiteral: false)
}
swift_error(none)
attributeswift_error(none)
属性的保留返回类型的失败方法Another option to preserve the return type is by disabling Objective-C - Swift error signature conversion at all with use of swift_error(none)
attribute:保留返回类型的另一种选择是通过使用
swift_error(none)
属性完全禁用 Objective-C - Swift 错误签名转换:
- (BOOL)failableMethodWithError:(NSError ** _Nullable)error __attribute__((swift_error(none)));
In this scenario you can return a scalar type from the failable method, but at the same time you will have to deal with NSErrorPointer
type:在这种情况下,您可以从可失败方法返回一个标量类型,但同时您将不得不处理
NSErrorPointer
类型:
func failableMethodWithError(_ error: NSErrorPointer) -> Bool {
if (/*error condition */) {
error?.pointee = NSError(domain: TDWErrorDomain, code: TDWErrorDomainErrorCode)
}
return true
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.