函数指针在swift中

ema*_*cos 2 pointers function objective-c ios swift

我正在学习本教程,特别是在使用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;
}
Run Code Online (Sandbox Code Playgroud)

对此,在init函数中是context变量给我带来的问题.

在上面的代码中,context是一个类型的变量:CFRunLoopSourceContext在apple文档中初始化这个对象是这样的

所以,我在初始化时,使用了以下代码,专注于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)
Run Code Online (Sandbox Code Playgroud)

功能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)

}
Run Code Online (Sandbox Code Playgroud)

但编译器给我以下错误信息: a c function pointer can only be formed from a reference to a 'func' or a literal closure

即使我做了以下关闭:

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)

    }
Run Code Online (Sandbox Code Playgroud)

我这样说:

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)
Run Code Online (Sandbox Code Playgroud)

给了我同样的错误.问题是什么 ?有小费吗

Mar*_*n R 7

如果您func RunLoopSourceScheduleRoutine()用作回调,则它需要是全局函数,而不是实例方法.

如果将回调定义为闭包,则需要将其标记为纯C回调:

let runLoopSourceScheduleRoutine: @convention(c) (UnsafeMutableRawPointer?, CFRunLoop?, CFRunLoopMode?) -> Void =
    { (info, rl, mode) in

        let obj = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
        // ...
}
Run Code Online (Sandbox Code Playgroud)

或者,将闭包表达式传递给编译器将类型推断为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)
Run Code Online (Sandbox Code Playgroud)

另请注意,您必须打开方法obj,而不是打开方法self.我建议使用GCD而不是performSelector(),这允许编译器检查是否使用正确的参数调用该方法:

let obj = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
let theContext = RunLoopContext(withSource: obj, andLoop: rl!)
DispatchQueue.main.async {
    obj.myMethod(theContext)
}
Run Code Online (Sandbox Code Playgroud)