我们可以直接从 Swift 使用基于 C 结构的 API 吗? [英] Can we use C struct based API directly from Swift?

查看:27
本文介绍了我们可以直接从 Swift 使用基于 C 结构的 API 吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我离开 WWDC 2016 时了解到我们应该警惕直接从 Swift 使用基于 C 的 struct API.在 在 Swift 3 中使用 GCD 进行并发编程中,谈到基于 C 的锁,它们非常具体:

I walked away from WWDC 2016 with the understanding that we should be wary about using C-based struct API directly from Swift. In Concurrent Programming With GCD in Swift 3, talking about C-based locks, they were very specific:

... 而在 Swift 中,由于您拥有整个 Darwin 模块,您实际上会看到基于 struct 的传统 C 锁.但是,Swift 假定任何 struct 都可以移动,并且这不适用于互斥锁或锁.所以我们真的不鼓励你使用 Swift 的这些类型的锁....

... And in Swift, since you have the entire Darwin module at your disposition, you will actually see the struct based traditional C locks. However, Swift assumes that anything that is struct can be moved, and that doesn't work with a mutex or with a lock. So we really discourage you from using these kind of locks from Swift. ...

...如果你想要一些...看起来像你在C中拥有的锁,那么你必须调用Objective-C并在Objective-C中引入一个基类,将你的锁作为ivar.

... And if you want something ... that looks like the locks that you have in C, then you have to call into Objective-C and introduce a base class in Objective-C that has your lock as an ivar.

然后你将公开 lockunlock 方法,以及一个 tryLock 如果你需要它,你将能够当您将此类子类化时,请从 Swift 调用....

And then you will expose lock and unlock methods, and a tryLock if you need it as well, that you will be able to call from Swift when you will subclass this class. ...

@implementation LockableObject {
    os_unfair_lock _lock;
}

- (void)lock   { os_unfair_lock_lock(&_lock); }
- (void)unlock { os_unfair_lock_unlock(&_lock); }
@end

但是,观看 WWDC 2019 开发出色的分析体验,我注意到作者直接从 Swift 使用 os_unfair_lock,没有使用这个 Objective-C 包装器,有效地:

However, watching WWDC 2019 Developing a Great Profiling Experience, I notice that the author is using os_unfair_lock directly from Swift, without this Objective-C wrapper, effectively:

private var workItemsLock = os_unfair_lock()

func subWorkItem(...) {
    ...
    os_unfair_lock_lock(&self.workItemsLock)
    ...
    os_unfair_lock_unlock(&self.workItemsLock)
    ...
}

根据经验,这种对 os_unfair_lock 的直接使用似乎有效,但这并不意味着什么.尊重 2016 年 WWDC 视频中的警告,我没有直接从 Swift 使用 os_unfair_lock.

Empirically, this sort of direct use of os_unfair_lock appears to work, but that doesn’t mean anything. Respecting the caveat in the 2016 WWDC video, I have refrained from using os_unfair_lock directly from Swift.

那么,问题是,在 2019 年的示例中,他们在使用此 API 时是否(有一点点)马虎?还是 2016 年视频的声明不正确?还是自 Swift 3 以来基于 C 的 struct 的处理发生了变化,现在使这种模式安全?

So, the question is, are they being (ever so slightly) sloppy in the use of this API in this 2019 sample? Or was the 2016 video incorrect in its claims? Or has the handling of C-based struct changed since Swift 3, now rendering this pattern safe?

推荐答案

使用 private var workItemsLock = os_unfair_lock() 的 API 示例可能会在运行时失败.

The API example of using private var workItemsLock = os_unfair_lock() can fail at runtime.

来自 C 的线程原语需要一个稳定的内存位置,因此要使用它们或另一个直接将这些原语之一作为其成员的结构,您必须使用 UnsafePointer.这样做的原因是 UnsafePointer API 一旦分配了一块内存,该内存是稳定的,并且不能被编译器移动或简单地复制.

The threading primitives from C need a stable memory location so to use them or another struct that has one of these primitives directly as a member of it you have to use UnsafePointer. The reason for this is that UnsafePointer APIs once they have allocated a chunk of memory that memory is stable and cannot be moved or trivially be copied by the compiler.

如果您像这样更改示例,它现在有效

If you change the example like this it is now valid

private var workItemsLock: UnsafeMutablePointer<os_unfair_lock> = {
    // Note, somewhere else this will need to be deallocated
    var pointer = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
    pointer.initialize(to: os_unfair_lock())
    return pointer
}()

func subWorkItem(...) {
    ...
    os_unfair_lock_lock(self.workItemsLock)
    ...
    os_unfair_lock_unlock(self.workItemsLock)
    ...
}

这篇关于我们可以直接从 Swift 使用基于 C 结构的 API 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆