在Objective-C中,我经常绕过块。我经常使用它们来实现有助于避免将内容存储到实例变量中的模式,从而避免线程/定时问题。
例如,我将它们分配给过CAAnimation孔,-[CAAnimation setValue:forKey:]以便在动画结束时执行该块。(Objective-C可以将块视为对象;您也可以这样做[someBlock copy]和[someBlock release]。)
CAAnimation
-[CAAnimation setValue:forKey:]
[someBlock copy]
[someBlock release]
但是,尝试在Swift和Objective-C中同时使用这些模式似乎很困难。( 编辑: 我们可以看到该语言仍在不断变化:已经对代码进行了修改,因此它可以在Xcode6-beta2上运行,而先前版本则在Xcode6-beta1上运行。)
例如,我无法转换AnyObject回阻止/关闭。以下从编译器产生错误:
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方式解决这个问题呢?
Block用函数类型参数化的泛型怎么样?
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