Dar*_*ust 15 closures block objective-c swift
在Objective-C中,我经常传递块.我经常使用它们来实现模式,以帮助避免将内容存储到实例变量中,从而避免线程/时序问题.
例如,我将它们分配给一个CAAnimationvia,-[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'
}
Run Code Online (Sandbox Code Playgroud)
我找到了一个解决方法,但它非常难看,恕我直言:在我的桥接标题中,我有:
static inline id blockToObject(void(^block)())
{
return block;
}
static inline void callBlockAsObject(id block)
{
((void(^)())block)();
}
Run Code Online (Sandbox Code Playgroud)
现在我可以在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)
}
Run Code Online (Sandbox Code Playgroud)
它可以工作,但是我需要为我想要使用的每种块类型使用一个新函数,而且我在编译器上进行攻击也不是很好.
那么有没有办法以纯粹的Swift方式解决这个问题?
GoZ*_*ner 10
Block使用函数类型参数化的泛型怎么样?
class Block<T> {
let f : T
init (_ f: T) { self.f = f }
}
Run Code Online (Sandbox Code Playgroud)
分配其中一个; 它将是一个子类型,AnyObject因此可以分配到字典和数组中.这对于尾随闭包语法来说似乎并不太繁琐.正在使用:
5> var b1 = Block<() -> ()> { print ("Blocked b1") }
b1: Block<() -> ()> = {
f = ...
}
6> b1.f()
Blocked b1
Run Code Online (Sandbox Code Playgroud)
以及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
Run Code Online (Sandbox Code Playgroud)
我喜欢GoZoner的解决方案 - 将块包装在一个自定义类中 - 但是由于你要求实际的"Swift方式"来执行块和AnyObject之间的转换,我只是给出了这个问题的答案:cast with unsafeBitCast.(我猜这与布莱恩陈的差不多一样reinterpretCast,不再存在.)
所以,在我自己的代码中:
typealias MyDownloaderCompletionHandler = @objc_block (NSURL!) -> ()
Run Code Online (Sandbox Code Playgroud)
注意:在Swift 2中,这将是:
typealias MyDownloaderCompletionHandler = @convention(block) (NSURL!) -> ()
Run Code Online (Sandbox Code Playgroud)
这是一个方向的演员:
// ... cast from block to AnyObject
let ch : MyDownloaderCompletionHandler = // a completion handler closure
let ch2 : AnyObject = unsafeBitCast(ch, AnyObject.self)
Run Code Online (Sandbox Code Playgroud)
这是另一个方向的演员:
// ... cast from AnyObject to block
let ch = // the AnyObject
let ch2 = unsafeBitCast(ch, MyDownloaderCompletionHandler.self)
// and now we can call it
ch2(url)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4470 次 |
| 最近记录: |