【问题标题】:How to store this Objective-C block inside a Swift variable?如何将此 Objective-C 块存储在 Swift 变量中?
【发布时间】:2015-09-25 06:46:19
【问题描述】:

这是 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 时,出现运行时错误:

我不知道还能做什么。这是一个空项目,里面真的没有代码。

【问题讨论】:

  • 你能试着用括号括住你的块定义吗? var theBlock: (()->Void)?
  • 是的,对不起。我已经把它放在括号里了。我编辑了问题
  • Ty 将块类型设置为var block : (@convention(block) () -> Void)?。 (Swift 2.0 - 对于 Swift 1.x 使用 @objc_block 而不是 @convention(block
  • @MatteoPacini 这对我不起作用。它对你有用吗?
  • @Jai 不,不幸的是。这是一个很奇怪的错误。我会做更多的测试然后回来。

标签: objective-c swift cocoa cocoa-touch objective-c-blocks


【解决方案1】:

在这种情况下,问题似乎来自 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]!

出于某种原因,NSMutableArray 上的泛型似乎没有被 Swift 采用。

尽管如此,如果你执行,你会得到一个运行时错误:

let block : MyType? = array[0]

【讨论】:

  • 谢谢!糟糕的是,我不能两次投票给你。哇.. 我正在调查您的解决方案到底做了什么。
  • 您需要一个类型才能使用 unsafeBitcast。由于您不能将() -&gt; Void 用作类型,因此诀窍是为其创建一个类型别名,因此您可以像在我的代码中一样使用.self 来引用它。然后你需要 unsafeBitcast 你的块到 typealias 类型。然后 Swift 将“记住”块的类型,因此右侧的 objc 块将转换为左侧的 Swift 闭包。我希望这会有所帮助。
猜你喜欢
  • 2014-02-24
  • 2016-05-11
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
相关资源
最近更新 更多