【问题标题】:Swift try inside Objective-C block在 Objective-C 块中快速尝试
【发布时间】:2018-03-16 15:56:18
【问题描述】:

我需要创建一个函数foo,它将一个抛出的闭包作为参数。我可以使用 Swift 或 ObjC 来实现它,但我需要能够从两者中调用它。

像这样:

// Swift
func bar() throws
func foo(_ block: () throws -> void)

foo {
  try bar()
}

// Objc
[self foo:^(
  [other barBar];
)];

我尝试使用 Swift 和 ObjC 来实现它,但没有成功。使用 Swift:

@objc
func foo(block: () throws -> Void)

我收到此错误:

方法不能标记@objc,因为参数1的类型不能在Objective-C中表示

如果我尝试用 ObjC 实现它:

typedef BOOL (^ThrowingBlock)(NSError **);
- (void)foo:(ThrowingBlock)block;

然后它不会转换为抛出的块 (as it would with a function):

func foo(_: (NSErrorPointer) -> Bool)

知道如何实现吗?

【问题讨论】:

  • 你可能做不到。正如错误消息告诉您的那样,Swift throws 函数不是可能的 Objective-C 参数类型。你必须改变你的欲望。你需要block的类型是Objective-C可以接受的类型。

标签: objective-c swift error-handling closures try-catch


【解决方案1】:

您可以使用NS_REFINED_FOR_SWIFT 宏在Objective-C 和Swift 之间提供统一的接口,在Swift 中使用throws,在Objective-C 中使用NSError **

来自Apple documentation

您可以在 Objective-C 方法声明中使用 NS_REFINED_FOR_SWIFT 宏,以在扩展中提供精炼的 Swift 接口,同时保持原始实现可从精炼的接口调用。例如,一个带有一个或多个指针参数的 Objective-C 方法可以在 Swift 中进行改进以返回一组值。

在您的情况下,您可以将 foo 声明为针对 Swift 精化,并在类扩展中添加相同的方法:

@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 调用者可以传递更好的throws 闭包。

【讨论】:

    猜你喜欢
    • 2017-03-20
    • 1970-01-01
    • 2016-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-23
    相关资源
    最近更新 更多