Неинициализированный указатель в стиле C, передаваемый в Apple Swift?

Я пытаюсь реализовать некоторые крипто-подпрограммы AES256 в Apple Swift, чтобы немного поиграть с совместимостью между ObjC, C и Swift, кодом и типами данных, и столкнулся с небольшой проблемой, и я надеюсь, что у кого-то есть предложения по чему-то, что я упустил из виду

Как большинство знакомо, общий шаблон в стиле C состоит в том, чтобы объявить неинициализированный указатель и затем передать его в функцию, где функция malloc() вызывает объект и указывает на него указатель; после завершения вызова функции указатель указывает на вновь созданный объект. Библиотеки Common Crypto используют это в некоторых местах; в частности, при создании нового объекта CCCryptor (на самом деле структура за кадром, похоже, определена с помощью CCCryptorRef для непрозрачной ссылки) - последний аргумент вызова CCCryptorCreate() является таким указателем и должен при заключение вызова функции, содержащее указатель на CCCryptorRef.

Swift вносит помехи в это - переменные не могут быть неинициализированы, они всегда либо имеют значение, либо имеют значение nil(/ необязательно), и поэтому я столкнулся с небольшим ударом здесь. Следующее не работает, потому что CCCryptorCreate (по праву) действует так, как будто я просто передаю nil в качестве последнего аргумента, которым я являюсь:

var myCryptorRef: CMutablePointer<Unmanaged<CCCryptorRef>?> = nil
CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128),
  CCOptions(kCCOptionECBMode), seedData.bytes(), UInt(kCCKeySizeAES256), 
  nil, myCryptorRef)

Но вы также не можете объявить его необязательным, например, так:

var myCryptorRef: CMutablePointer<Unmanaged<CCCryptorRef>?>?

Или как не указатель типа:

var myCryptoRef: Unmanaged<CCCryptorRef>?
CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128),
  CCOptions(kCCOptionECBMode), seedData.bytes(), UInt(kCCKeySizeAES256), 
  nil, &myCryptorRef)

Поскольку то, что ожидает CCCryptorCreate, является либо неинициализированным указателем на CCCryptorRef, либо уже созданным пользователем malloc() CCCryptorRef, попытка передать ему адрес еще не инициализированного объекта не проходит очень хорошо, как вы могли ожидать.

Итак, все сводится к следующему: может ли кто-нибудь придумать способ инициализации этой структуры CCCryptor перед вызовом CCCryptorCreate (стандартный метод структуры init для Swift с присвоением имен всем переменным внутри структуры, похоже, не работает), или некоторые альтернативная конструкция, которая позволила бы мне сохранить концепцию C неинициализированного указателя для использования таким образом? Спасибо за любые предложения, которые вы можете иметь.

Добавление для ясности из комментариев: Swift интерпретирует вызов CCCryptorCreate() следующим образом:

CCCryptorCreate(op: CCOperation, alg: CCAlgorithm, options: CCOptions, 
  key: CConstVoidPointer, keyLength: UInt, iv: CConstVoidPointer, 
  cryptorRef: CMutablePointer<Unmanaged<CCCryptor>?>)

Дополнительное редактирование для некоторых других вещей, которые я попробовал: просто чтобы быть по-настоящему абсурдным, я попробовал следующее, но это также не сработало (EXC_BAD_ACCESS при вызове fromOpaque):

var someMem = malloc(UInt(sizeof(CCCryptor)))
var crashTime = Unmanaged<CCCryptor>.fromOpaque(someMem)

Кроме того, упоминается каждое место CCCryptor или CCCryptorRef, я пробовал любой из них - в CommonCrypto/CommonCryptor.h, CCCryptorRef определяется следующим образом:

typedef struct _CCCryptor *CCCryptorRef

Поэтому, хотя существующие примеры кода Objective-C используют CCCryptorRef, я тоже пытался.

2 ответа

Решение

Попробуй это:

var myCryptor: Unmanaged<CCCryptor>?

CCCryptorCreate( .... , &myCryptor )

От использования Swift с какао и Objective-C

Если вы объявили функцию, подобную этой:

func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ }

Вы можете назвать это любым из следующих способов:

var x: Float = 0.0 
var p: CMutablePointer<Float> = nil 
var a: Float[] = [1.0, 2.0, 3.0] 
takesAMutablePointer(nil) 
takesAMutablePointer(p) 
takesAMutablePointer(&x) 
takesAMutablePointer(&a)

Вы также должны проверить это и преобразовать Unmanaged ссылка на то, что управляется.

Вот пример, который работает на бета 3, используя тип из librabbitmq:

let envelopePtr = UnsafePointer<amqp_envelope_t>.alloc(1)
reply = amqp_consume_message(connection, envelopePtr, nil, 0)
let envelope = envelopePtr.memory
Другие вопросы по тегам