Можем ли мы использовать API на основе C-структур непосредственно из Swift?
Я ушел с WWDC 2016 с пониманием того, что нам следует опасаться использования C-based struct
API прямо из Swift. В параллельном программировании с GCD в Swift 3, говоря о блокировках на основе C, они были очень конкретными:
... А в Swift, поскольку у вас есть весь модуль Darwin, вы фактически увидите
struct
на основе традиционных замков C. Однако Свифт предполагает, что все, чтоstruct
можно перемещать, и это не работает с мьютексом или блокировкой. Поэтому мы действительно не рекомендуем вам использовать подобные блокировки от Swift....... И если вам нужно что-то... похожее на блокировки, которые есть у вас в C, тогда вам нужно вызвать Objective-C и ввести базовый класс в Objective-C, который имеет вашу блокировку как ivar.
А потом выставишь
lock
а такжеunlock
методы иtryLock
если он вам тоже нужен, вы сможете вызывать его из Swift, когда создадите подкласс этого класса....@implementation LockableObject { os_unfair_lock _lock; } - (void)lock { os_unfair_lock_lock(&_lock); } - (void)unlock { os_unfair_lock_unlock(&_lock); } @end
Однако, наблюдая за WWDC 2019 Developing a Great Profiling Experience, я заметил, что автор используетos_unfair_lock
непосредственно из Swift, без этой оболочки Objective-C, эффективно:
private var workItemsLock = os_unfair_lock()
func subWorkItem(...) {
...
os_unfair_lock_lock(&self.workItemsLock)
...
os_unfair_lock_unlock(&self.workItemsLock)
...
}
Эмпирически такое прямое использование os_unfair_lock
похоже, работает, но это ничего не значит. Принимая во внимание предостережение в видео WWDC 2016 года, я воздержался от использованияos_unfair_lock
прямо из Swift.
Итак, вопрос в том, являются ли они (хоть немного) небрежными в использовании этого API в этом образце 2019 года? Или видео 2016 года было неверным в своих претензиях? Или имеет обработку на основе Cstruct
изменился со времен Swift 3, теперь этот шаблон становится безопасным?
1 ответ
Пример использования API private var workItemsLock = os_unfair_lock()
может честно во время выполнения.
Примитивы потоковой передачи из C нуждаются в стабильной области памяти, поэтому, чтобы использовать их или другую структуру, которая имеет один из этих примитивов непосредственно в качестве члена, вы должны использовать UnsafePointer
. Причина в том, чтоUnsafePointer
API-интерфейсы после того, как они выделили кусок памяти, эта память стабильна и не может быть перемещена или тривиально скопирована компилятором.
Если вы измените пример таким образом, он теперь действителен
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)
...
}