如何将这个Objective-C块存储在Swift变量中?

4

这里是Objective-C的代码块:

@property (copy) void (^anObjcBlock)();

anObjcBlock = ^{
    NSLog(@"Yea man this thing works!!");
};
NSMutableArray *theArrayThatHasTheBlockInItAtIndexZero = [NSMutableArray array];
[theArrayThatHasTheBlockInItAtIndexZero addObject:anObjBlock];

这是我在Swift中所做的:

var theBlock: (()->Void)?

theBlock = theArrayThatHasTheBlockInItAtIndexZero[0] as? ()->Void
// Now call the block
theBlock!()

但是我遇到了运行时错误。
基本上,theBlock = theArrayThatHasTheBlockInItAtIndexZero[0] as? ()->Void语句会使theBlock为空,因为as?失败了。当我将该语句更改为theBlock = theArrayThatHasTheBlockInItAtIndexZero[0] as! ()->Void时,我会得到一个运行时错误:
enter image description here 我不知道还能做什么。这是一个空项目,实际上里面没有任何代码。

你能否尝试用括号将你的块定义包围起来? var theBlock: (()->Void)? - Paul Slm
抱歉,我已经把它括号起来了。我修改了问题。 - Just a coder
尝试将块类型设置为 var block : (@convention(block) () -> Void)?。(Swift 2.0 - 对于 Swift 1.x,请使用 @objc_block 而不是 @convention(block)。 - Matteo Pacini
@Jai,你能发一下初始化数组的代码吗? - Matteo Pacini
你能告诉我们运行时错误是什么吗? - Tommy
显示剩余2条评论
1个回答

9

看起来,在这种情况下,问题出在NSMutableArray上。

[NSMutableArray objectAtIndex:] 在 Objective-C 中返回 id,在 Swift 中被翻译为 AnyObject

如果你尝试将 AnyObject 强制转换为 () ->Void,就会出现错误。

以下是一种解决方法:

// Create your own typealias (we need this for unsafeBitcast)
typealias MyType = @convention(block) () -> Void

// Get the Obj-C block as AnyObject
let objcBlock : AnyObject = array.firstObject! // or [0]

// Bitcast the AnyObject Objective-C block to a "Swifty" Objective-C block (@convention(block)) 
// and then assign the result to a variable of () -> Void type

let block : () -> Void = unsafeBitCast(objcBlock, MyType.self)

// Call the block
 
block()

这段代码对我来说可用。

有趣的事实

如果您将Objective-C代码编辑成以下形式...

// Typedef your block type
typedef void (^MyType)();

// Declare your property as NSArray of type MyType
@property (strong) NSArray<MyType>* array;

现在,Swift将数组类型报告为[MyType]!

由于某种原因,Swift似乎没有识别< strong> NSMutableArray 上的泛型。

尽管如此,如果您执行以下操作,将会收到运行时错误:

let block : MyType? = array[0]

1
谢谢!可惜我不能给你点赞两次。哇。。。我正在研究你的解决方案到底做了什么。 - Just a coder
1
你需要一个类型来使用unsafeBitcast。由于你不能将() -> Void用作类型,所以诀窍是为其创建一个typealias,这样你就可以像在我的代码中一样使用.self来引用它。然后,你需要将你的块不安全地转换为typealias类型。Swift将“记住”块的类型,因此右侧的objc块将转换为左侧的Swift闭包。希望这能帮到你。 - Matteo Pacini

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接