如何访问课程" self"实例,在给定以下代码的情况下调用类实例方法。如果我尝试self.callSomeClassIntance(),如图所示,我得到一个" A C函数指针不能形成一个捕获上下文的闭包"来自编译器的错误。我在尝试info.callSomeClassInstance(),但是这将给出一个"没有成员callSomeClassInstance"错误。如果删除了一行代码xxxx.callSomeClassIntance(),代码将正确触发时间。
import Foundation
class Foo {
func callSomeClassIntance() {}
func start() {
let runLoop : CFRunLoopRef = CFRunLoopGetCurrent();
var context = CFRunLoopTimerContext(version: 0, info: unsafeBitCast(self, UnsafeMutablePointer<Void>.self), retain: nil, release: nil, copyDescription: nil)
let timer : CFRunLoopTimerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, 0.1, 3.0, 0, 0, cfRunloopTimerCallback(), &context);
CFRunLoopAddTimer(runLoop, timer, kCFRunLoopCommonModes);
CFRunLoopRun()
}
func cfRunloopTimerCallback() -> CFRunLoopTimerCallBack {
return { (cfRunloopTimer, info) -> Void in
print("Fire timer...")
// need self context here to call class instance methods
self.callSomeClassIntance()
}
}
}
答案 0 :(得分:3)
与How to use instance method as callback for function which takes only func or literal closure一样,CFRunLoopTimerCallBack
必须是一个全局函数或一个不捕获上下文的闭包。
特别是,该闭包不能捕获self
因此必须
将void指针从上下文中的info
转换回实例
指针。
您不一定需要cfRunloopTimerCallback()
功能,
闭包可以直接作为参数传递:
class Foo {
func callSomeClassIntance() {}
func start() {
let runLoop = CFRunLoopGetCurrent();
var context = CFRunLoopTimerContext()
context.info = UnsafeMutablePointer<Void>(Unmanaged.passUnretained(self).toOpaque())
let timer = CFRunLoopTimerCreate(kCFAllocatorDefault, 0.1, 3.0, 0, 0, {
(cfRunloopTimer, info) -> Void in
let mySelf = Unmanaged<Foo>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
mySelf.callSomeClassIntance()
}, &context);
CFRunLoopAddTimer(runLoop, timer, kCFRunLoopCommonModes);
CFRunLoopRun()
}
}
这里我使用了Unmanaged
来实现实例指针和void指针之间的转换。它看起来更复杂但强调了这一点
传递未包含的引用。 unsafeBitCast()
如同
@ nhgrif的答案可以替代使用。
您还可以定义类似于Objective-C __bridge
的函数,
比较How to cast self to UnsafeMutablePointer<Void> type in swift。
答案 1 :(得分:2)
我们不需要捕获self
,因为我们已经将其传入。
当您为计时器创建上下文时,您将self
放入允许C代码处理它的格式中,这是一个无效指针:
unsafeBitCast(self, UnsafeMutablePointer<Void>.self)
此代码返回指向self
的void指针。这就是您在创建上下文时为info
参数传入的内容。
在创建上下文时,无论您为info
参数传递了什么,都会传递info
函数的CFRunLoopTimerCallback
参数。因此,我们需要对unsafeBitCast(info, Foo.self)
参数应用逆运算(info
):
func cfRunloopTimerCallback() -> CFRunLoopTimerCallBack {
return { _, info in
let grabSelf = unsafeBitCast(info, Foo.self)
grabSelf.callSomeClassIntance()
}
}