在Objective-C块内快速尝试
我需要创建一个函数 foo
,该函数将引发闭包作为参数。我可以使用Swift或ObjC来实现它,但是我需要能够从两者中调用它。
I need to create a function foo
that takes a throwing closure as a parameter. I can implement it with either Swift or ObjC but I need to be able to call it from both.
就像这样:
// Swift
func bar() throws
func foo(_ block: () throws -> void)
foo {
try bar()
}
and
// Objc
[self foo:^(
[other barBar];
)];
我试图用Swift和ObjC来实现它而没有成功。使用Swift:
I tried to implement it with both Swift and ObjC without succes. With Swift:
@objc
func foo(block: () throws -> Void)
我收到此错误:
不能将方法标记为@objc,因为参数1的类型不能在Objective-C中表示。
Method cannot be marked @objc because the type of the parameter 1 cannot be represented in Objective-C
如果我尝试实现它与ObjC:
If I try to implement it with ObjC:
typedef BOOL (^ThrowingBlock)(NSError **);
- (void)foo:(ThrowingBlock)block;
然后它不会转换为抛出的块(就像使用函数一样):
Then it does not translate to a block that throws (as it would with a function):
func foo(_: (NSErrorPointer) -> Bool)
有什么办法实现这一目标吗?
Any idea how to achieve this?
您可以使用 NS_REFINED_FOR_SWIFT
宏在Objective-C和Swift之间提供统一的接口,在Swift中抛出
,在Objective-C中出现 NSError **
。
You could use the NS_REFINED_FOR_SWIFT
macro to provide a unified interface between Objective-C and Swift, with throws
in Swift and NSError **
in Objective-C.
从 Apple文档:
您可以在Objective-C方法上使用NS_REFINED_FOR_SWIFT宏声明以在扩展中提供精致的Swift接口,同时保持原始实现n可从改进的界面调用。例如,可以在Swift中对采用一个或多个指针参数的Objective-C方法进行改进,以返回一个元组值。
You can use the NS_REFINED_FOR_SWIFT macro on an Objective-C method declaration to provide a refined Swift interface in an extension, while keeping the original implementation available to be called from the refined interface. For instance, an Objective-C method that takes one or more pointer arguments could be refined in Swift to return a tuple of values.
在您的情况下,您可以声明 foo
为Swift进行了精炼,并在类扩展中添加了相同的方法:
In your case you can declare foo
as refined for Swift, and add a same method, in a class extension:
@interface MyClass : NSObject
- (void)foo:(void (^)(NSError **))block NS_REFINED_FOR_SWIFT;
@end
以及在Swift中:
extension MyClass {
func foo(block: @escaping () throws -> Void) {
// Objective-C's `foo` is now imported as `__foo`
__foo { errPtr in
do {
try block()
} catch {
errPtr?.pointee = error as NSError
}
}
}
}
现在您可以从两个地方调用 foo
,区别在于Objective-C代码将需要传递 NSError **
阻止,而Swift调用者可以通过更好的抛出
闭包。
Now you can call foo
from both worlds, with the distinction that Objective-C code will need to pass a NSError **
block, while Swift callers can pass a nicer throws
closure.