Swift try inside Objective-C block

不问归期 提交于 2019-12-10 14:57:06

问题


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.

Like this:

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

foo {
  try bar()
}

and

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

I tried to implement it with both Swift and ObjC without succes. With Swift:

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

I get this error:

Method cannot be marked @objc because the type of the parameter 1 cannot be represented in Objective-C

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?


回答1:


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.

From the Apple documentation:

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.

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

and in 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
            }
        }
    }
}

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.



来源:https://stackoverflow.com/questions/49324917/swift-try-inside-objective-c-block

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!