快速函数指针
2016-12-23
3709
我正在关注这个 教程 ,特别是我在用 Swift 语言转换这个函数时遇到了问题:
- (id)init
{
CFRunLoopSourceContext context = {0, self, NULL, NULL, NULL, NULL, NULL,
&RunLoopSourceScheduleRoutine,
RunLoopSourceCancelRoutine,
RunLoopSourcePerformRoutine};
runLoopSource = CFRunLoopSourceCreate(NULL, 0, &context);
commands = [[NSMutableArray alloc] init];
return self;
}
其中,在 init 函数中
context
变量给我带来了问题。
在上面的代码中,context 是一个类型为:
CFRunLoopSourceContext
的变量,而苹果文档中这个对象的初始化是
像这个
因此,我在初始化时使用了以下代码,专注于
schedule
参数:
var context = CFRunLoopSourceContext(version: 0, info: bridge(obj: self) ,
retain: nil,
release: nil,
copyDescription: nil,
equal: nil,
hash: nil,
schedule: RunLoopSourceScheduleRoutine,
cancel: nil,
perform: nil)
函数
RunLoopSourceScheduleRoutine
如下所示:
func RunLoopSourceScheduleRoutine(info:UnsafeMutableRawPointer? ,rl:CFRunLoop? , mode:CFRunLoopMode?) {
let obj : RunLoopSource = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
let theContext = RunLoopContext(withSource: obj, andLoop: rl!)
performSelector(onMainThread: #selector(myMethod), with: theContext, waitUntilDone: false)
}
但编译器给出了以下错误消息:
c 函数指针只能由对“func”或文字闭包的引用形成
即使我创建了以下闭包:
let runLoopSourceScheduleRoutine = { (info:UnsafeMutableRawPointer? ,rl:CFRunLoop? , mode:CFRunLoopMode?)-> Void in return
let obj : RunLoopSource = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
let theContext = RunLoopContext(withSource: obj, andLoop: rl!)
performSelector(onMainThread: #selector(myMethod), with: theContext, waitUntilDone: false)
}
我这样写:
var context = CFRunLoopSourceContext(version: 0, info: bridge(obj: self) ,
retain: nil,
release: nil,
copyDescription: nil,
equal: nil,
hash: nil,
schedule: runLoopSourceScheduleRoutine,
cancel: nil,
perform: nil)
也给出了相同的错误。 问题是什么? 有什么提示吗
1个回答
如果您使用
func RunLoopSourceScheduleRoutine()
作为回调,那么它必须是
全局函数
,而不是实例方法。
如果您将回调定义为闭包,那么它需要标记为纯 C 回调:
let runLoopSourceScheduleRoutine: @convention(c) (UnsafeMutableRawPointer?, CFRunLoop?, CFRunLoopMode?) -> Void =
{ (info, rl, mode) in
let obj = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
// ...
}
或者,将闭包表达式传递给编译器,编译器会将类型推断为 C 回调:
var context = CFRunLoopSourceContext(version: 0, info: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) ,
retain: nil,
release: nil,
copyDescription: nil,
equal: nil,
hash: nil,
schedule: { (info, rl , mode) in
let obj = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
// ...
}, cancel: nil,
perform: nil)
还请注意,您必须在
obj
上调用该方法,而不是在
self
上调用该方法。
我建议使用 GCD 而不是
performSelector()
,这允许
编译器检查该方法是否使用正确的参数调用:
let obj = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
let theContext = RunLoopContext(withSource: obj, andLoop: rl!)
DispatchQueue.main.async {
obj.myMethod(theContext)
}
Martin R
2016-12-23