Tengo una siguiente estructura de estilo C en la biblioteca:
typedef struct ServiceParam { const char *name; const char *value; } ServiceParam;Estoy interesado en inicializar una matriz de estas estructuras de Swift, esto es lo que he intentado:
let cHeaders = headers.map{ServiceParam(name: $0.name, value: $0.value)}Pero recibiendo la siguiente advertencia:
Pasar 'Cadena' al parámetro, pero el argumento 'valor' debe ser un puntero que sobreviva a la llamada a 'init(nombre:valor:)'
¡Los parámetros C de name y value se convierten en forma de UnsafePointer<CChar>! y el tipo de entrada es (name: String, value: String) , es decir, Swift-tuple, pero soy flexible con respecto a cambiar el tipo inicial.
Entonces, todo el ejemplo mínimo se ve de la siguiente manera:
public func setParams(headers: [(name: String, value: String)] = []) { let cHeaders = headers.map{ServiceParam(name: $0.name, value: $0.value)} // Do the work with `cHeaders` }¿Cuál sería la mejor manera de inicializar la estructura de estilo C antes mencionada desde el sitio de llamadas de Swift?
La estructura ServiceParam se usa temporalmente solo durante la llamada a la función principal, pero las cadenas de name y value se almacenan como pares de C++ en una matriz y su duración continúa después de que la función regresa:
Mas tarde:
const auto paramPair = std::make_pair(params->name, params->value); instance_variable_array.push_back(paramPair);Al pasar una cadena Swift a una función C tomando un argumento const char * , se crea automáticamente una representación de cadena C temporal. Sin embargo, esa cadena C solo es válida durante la llamada a la función. Eso es lo que sucede en
ServiceParam(name: $0.name, value: $0.value) y provoca las advertencias. Hay un método withCString que se puede usar para crear una representación de cadena C que es válida en algún ámbito:
name.withCString { cName in value.withCString { cValue in let sp = ServiceParam(name: cName, value: cValue) // Do something with sp ... } }pero nuevamente, los punteros de cadena C no son válidos después de que la ejecución haya salido de estos ámbitos.
Para una vida útil más larga de las cadenas C, puede duplicar la memoria y liberarla más tarde:
let cHeaders = headers.map{ ServiceParam(name: strdup($0.name), value: strdup($0.value)) } // Do the work with `cHeaders` for header in cHeaders { free(UnsafeMutablePointer(mutating: header.name)) free(UnsafeMutablePointer(mutating: header.value)) }