小编典典

铸造瓶盖/块

swift

在Objective-C中,我经常绕过块。我经常使用它们来实现有助于避免将内容存储到实例变量中的模式,从而避免线程/定时问题。

例如,我将它们分配给过CAAnimation孔,-[CAAnimation setValue:forKey:]以便在动画结束时执行该块。(Objective-C可以将块视为对象;您也可以这样做[someBlock copy][someBlock release]。)

但是,尝试在Swift和Objective-C中同时使用这些模式似乎很困难。( 编辑:
我们可以看到该语言仍在不断变化:已经对代码进行了修改,因此它可以在Xcode6-beta2上运行,而先前版本则在Xcode6-beta1上运行。)

例如,我无法转换AnyObject回阻止/关闭。以下从编译器产生错误:

override func animationDidStop(anim: CAAnimation!, finished flag: Bool)
{
    let completion : AnyObject! = anim.valueForKey("completionClosure")
    (completion as (@objc_block ()->Void))()
    // Cannot convert the expression's type 'Void' to type '@objc_block () -> Void'
}

我找到了一种解决方法,但恕我直言,这很丑陋:在我的桥接标题中,我有:

static inline id blockToObject(void(^block)())
{
    return block;
}

static inline void callBlockAsObject(id block)
{
    ((void(^)())block)();
}

现在我可以在Swift中做到这一点:

func someFunc(completion: (@objc_block ()->Void))
{
    let animation = CAKeyframeAnimation(keyPath: "position")
    animation.delegate = self
    animation.setValue(blockToObject(completion), forKey: "completionClosure")
    …
}

override func animationDidStop(anim: CAAnimation!, finished flag: Bool)
{
    let completion : AnyObject! = anim.valueForKey("completionClosure")
    callBlockAsObject(completion)
}

它可以工作,但是我需要为每个要使用的每种块类型添加一个新函数,并且我在围绕编译器乱搞,这也不是一件好事。

那么有没有办法以一种纯粹的Swift方式解决这个问题呢?


阅读 292

收藏
2020-07-07

共1个答案

小编典典

Block用函数类型参数化的泛型怎么样?

class Block<T> {
  let f : T
  init (_ f: T) { self.f = f }
}

分配其中之一;它是的子类型,AnyObject因此可以分配给字典和数组。这似乎不太麻烦,尤其是在 尾随闭包 语法中。正在使用:

  5> var b1 = Block<() -> ()> { print ("Blocked b1") }
b1: Block<() -> ()> = {
  f = ...
}
  6> b1.f()
Blocked b1

另一个Block推断类型的例子:

 11> var ar = [Block { (x:Int) in print ("Block: \(x)") }]
ar: [Block<(Int) -> ()>] = 1 value {
  [0] = {
    f = ...
  }
}
 12> ar[0].f(111)
Block: 111
2020-07-07