$ swift --version
Apple Swift version 4.0 (swiftlang-900.0.63.10 clang-900.0.36)
Target: x86_64-apple-macosx10.9
Swift ist praktisch, weil es das Aufrufen von C-Sprachfunktionen erleichtert. Sie können Swifts Array
Dies wird durch den Mechanismus erreicht, dass "Array
Aber wenn es um ein zweidimensionales Array geht, funktioniert es nicht. Doppelzeiger werden verwendet, wenn ein zweidimensionales Array in C empfangen wird. Zum Beispiel in C.
void f0(const int * const * p);
Aus Swifts Sicht ist die Funktion definiert als
func f0(_ p: UnsafePointer<UnsafePointer<CInt>?>!)
Wird interpretiert als. Wenn sich auf der Swift-Seite ein let arr: Array <Array <CInt >>
befindet, funktioniert Folgendes nicht.
let arr: Array<Array<CInt>> = [ [0, 1, 2], [3, 4, 5] ]
f0(arr) //Kompilierungsfehler
Denn was Sie erhalten, wenn Sie "Array <Array
UnsafePointer<Array<CInt>>
Und
UnsafePointer<UnsafePointer<CInt>?>
Weil es nicht ist.
Wenn Sie sich also die Transformation ansehen, die "UnsafePointer
func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Array.Element>) throws -> R) rethrows -> R
Kann gefunden werden. Sie können es verwenden, um Code wie folgt zu schreiben: Dies ** wird kompiliert, sollte aber nicht. ** ** **
let arr: Array<Array<CInt>> = [ [0, 1, 2], [3, 4, 5] ]
let bufPtrArr: Array<UnsafeBufferPointer<CInt>> = arr.map {
return $0.withUnsafeBufferPointer { $0 }
}
let ptrArr: Array<UnsafePointer<CInt>?> = bufPtrArr.map { $0.baseAddress }
f0(ptrArr)
Dies liegt daran, dass der Zeiger, der an das Schließen des Arguments der Methode "withUnsafeBufferPointer" übergeben wird, nur während der Ausführung dieser Methode verwendet werden sollte.
Es wird für rekursive Aufrufe verwendet, da Sie die Arrays einzeln in Zeiger konvertieren müssen, die nur während "withUnsafeBufferPointer" verwendet werden können. Nach dem Konvertieren eines Arrays mit "withUnsafeBufferPointer" besteht die Prozedur darin, ein Array von Zeigern zu erstellen, indem das nächste Array innerhalb der Methode konvertiert wird.
Dieser rekursive Prozess ist oft schwer zu schreiben. Machen wir ihn also zu einer Erweiterungsmethode von "Array" zur Wiederverwendung und holen "Array <UnsafeBufferPointer withUnsafeBufferPointerArray
gemacht.
extension Array {
public func withUnsafeBufferPointerArray<T, R>(_ body: (Array<UnsafeBufferPointer<T>>) -> R) -> R
where Element == Array<T>
{
var buffers = Array<UnsafeBufferPointer<T>>()
var result: R?
func recurse(body: (Array<UnsafeBufferPointer<T>>) -> R)
{
let i = buffers.count
guard i < self.count else {
result = body(buffers)
return
}
self[i].withUnsafeBufferPointer { (buf: UnsafeBufferPointer<T>) in
buffers.append(buf)
recurse(body: body)
}
}
recurse(body: body)
return result!
}
}
Die Verwendung einer In-Function-Funktion erleichtert das Schreiben eines Prozesses, der diese Art von Statusoperation und rekursivem Aufruf kombiniert. Ich mag es nicht, den Rückgabewert so oft zu kopieren, wie es Elemente gibt, also verwende ich "Optional" und "!".
Jetzt können Sie "f0" wie folgt aufrufen.
let arr: Array<Array<CInt>> = [ [0, 1, 2], [3, 4, 5] ]
arr.withUnsafeBufferPointerArray { (bufPtrArr: Array<UnsafeBufferPointer<CInt>>) in
let ptrArr: Array<UnsafePointer<CInt>?> = bufPtrArr.map { $0.baseAddress }
f0(ptrArr)
}
Als praktisches Beispiel OpenGL ES
void glShaderSource(
GLuint shader,
GLsizei count,
const GLchar * const *string,
const GLint *length);
Bei Anruf
public static func shaderSource(_ id: GLuint,
_ strings: Array<Array<GLchar>>)
{
strings.withUnsafeBufferPointerArray { (buffers: Array<UnsafeBufferPointer<GLchar>>) in
glShaderSource(id,
GLsizei(buffers.count),
buffers.map { $0.baseAddress },
buffers.map { GLint($0.count) })
}
}
Es ist wie es ist. Es ist schön, dass die Argumente "count", "string" und "length" leicht aus "Puffern" konstruiert werden können.
Recommended Posts