SwiftからCルーチンを呼び出す方法はありますか?
多くのiOS/AppleライブラリはCのみであり、それらを呼び出すことができるようにしたいです。
たとえば、Swiftからobjcランタイムライブラリを呼び出すことができます。
特に、iOS Cヘッダーをどのようにブリッジしますか?
はい、もちろんApples Cライブラリとやり取りできます。 ここ の方法を説明します。
基本的に、Cタイプ、CポインターなどはSwiftオブジェクトに変換されます。たとえば、SwiftのC int
はCInt
です。
CとSwiftを橋渡しする方法について、ちょっとした説明として使用できる別の質問のために、小さな例を作成しました。
main.Swift
import Foundation
var output: CInt = 0
getInput(&output)
println(output)
UserInput.c
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
cliinput-Bridging-Header.h
void getInput(int *output);
ここ は元の答えです。
コンパイラは、Objective-Cの場合と同様に、C APIをSwiftに変換します。
import Cocoa
let frame = CGRect(x: 10, y: 10, width: 100, height: 100)
import Darwin
for _ in 1..10 {
println(Rand() % 100)
}
ドキュメントの Objective-C APIとの対話 を参照してください。
あなたが私と同じようにXCodeを初めて使い、 Leandroの答え に投稿されたスニペットを試してみたい場合に備えて:
この投稿 には、clangの モジュールサポート を使用してこれを行う方法に関する適切な説明もあります。
CommonCryptoプロジェクトでこれを行う方法の観点からフレーム化されていますが、一般的には、Swift内から使用する他のCライブラリでも機能するはずです。
Zlibでこれを簡単に試しました。新しいiOSフレームワークプロジェクトを作成し、次の内容のmodule.modulemapファイルを含むディレクトリzlibを作成しました。
module zlib [system] [extern_c] {
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/zlib.h"
export *
}
次に、[ターゲット]-> [ライブラリとバイナリをリンク]で、[アイテムの追加]を選択し、libz.tbdを追加しました。
この時点でビルドすることもできます。
その後、次のコードを書くことができました。
import zlib
public class Zlib {
public class func zlibCompileFlags() -> UInt {
return zlib.zlibCompileFlags()
}
}
上記の場合を除いて、zlibライブラリ名を前に置くhaveをしないでくださいSwift class func the C関数と同じで、修飾がないと、Swift funcは、アプリケーションが停止するまで繰り返し呼び出されます。
C++の場合、ポップアップするこのエラーがあります:
"_getInput", referenced from:
C++ヘッダーファイルも必要です。関数に c-linkage を追加し、ブリッジヘッダーにヘッダーファイルを含めます。
Swift 3
UserInput.h
#ifndef USERINPUT_H
#define USERINPUT_H
#ifdef __cplusplus
extern "C"{
#endif
getInput(int *output);
#ifdef __cplusplus
}
#endif
UserInput.c
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
main.Swift
import Foundation
var output: CInt = 0
getInput(&output)
print(output)
cliinput-Bridging-Header.h
#include "UserInput.h"
元の これを説明するビデオ
ポインターを扱う場合、それはかなり異なるボールのように見えます。 C POSIX read
システムコールを呼び出すためにこれまでに持っているものは次のとおりです。
enum FileReadableStreamError : Error {
case failedOnRead
}
// Some help from: http://stackoverflow.com/questions/38983277/how-to-get-bytes-out-of-an-unsafemutablerawpointer
// and https://Gist.github.com/kirsteins/6d6e96380db677169831
override func readBytes(size:UInt32) throws -> [UInt8]? {
guard let unsafeMutableRawPointer = malloc(Int(size)) else {
return nil
}
let numberBytesRead = read(fd, unsafeMutableRawPointer, Int(size))
if numberBytesRead < 0 {
free(unsafeMutableRawPointer)
throw FileReadableStreamError.failedOnRead
}
if numberBytesRead == 0 {
free(unsafeMutableRawPointer)
return nil
}
let unsafeBufferPointer = UnsafeBufferPointer(start: unsafeMutableRawPointer.assumingMemoryBound(to: UInt8.self), count: numberBytesRead)
let results = Array<UInt8>(unsafeBufferPointer)
free(unsafeMutableRawPointer)
return results
}