ここのところLinux上でSwiftを使っていて、Tipsというか困ったこと(Troubles)が知識としてたまってきたのでまとめてみます。
また多分いろいろ出てくると思うので、とりあえず、第1弾です。
Stringのformatが使えない
これ、結構困ります。
例えば、
こういう感じで数値を整形して文字列にしたい場合によく使うと思うのですが、このイニシャライザが全く使えません。。
実際にIBM Swift Sandboxで試してみてください。
Error running code: fatal error: init(format:locale:arguments:) is not yet implemented: file Foundation/NSString.swift, line 1232 0 swift 0x0000000002f4abf8 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 40 1 swift 0x0000000002f493f6 llvm::sys::RunSignalHandlers() + 54 2 swift 0x0000000002f4b726 3 libpthread.so.0 0x00007fb5ff75cd10 4 libswiftCore.so 0x00007fb5f5676ac3 _TTSf4s_s_s_n___TFs16_assertionFailedFTVs12StaticStringSSS_Su_T_ + 147 5 libFoundation.so 0x00007fb5f7c0f21f 6 libFoundation.so 0x00007fb5f7c7ef07 7 libFoundation.so 0x00007fb5f7c7ee74 :
このようなエラーが出てしまうと思います。init(format:locale:arguments:) is not yet implementedと出ています。localeとか指定していないのに・・・。
これは、githubのswiftのソースコードを見てみると原因がわかります。
まず、Foundation/NSStringAPI.swiftのStringクラスのコードを見ると...
このように、String(format: format, locale: nil, arguments: arguments)が呼び出されています。
その中では、NSString(format: format, locale: locale, arguments: $0)が呼び出されているようです。
では、NSStringの中も見てみましょう。これは、https://github.com/apple/swift-corelibs-foundationの方のリポジトリにソースがあります。
ファイルは、先ほどのSwift Sandboxでもエラーに出ていた、NSString.swiftです。
はい、NSUnimplemented()ですね。。
しかし、よく見るとNSString(format: NSString, _ args: CVarArgType...)が使えるようです!
ということで、Stringの代わりにNSStringを使って書き直してみましょう。
これは、IBM Swift Sandboxでもちゃんと動きます。
Stringとして使う場合はいちいちbridge()しないといけないのが面倒くさいですが・・・(Macなら、 as String でもいけます。)
print()がバッファリングされる
これは、MacでもLinuxでも同様かもしれません。
普通は特にそれほど困ることはないと思いますが、gulpを使ってswiftでビルドしたプログラムを実行させていると、print()の結果がバッファリングされてしまい、stdoutに反映されません。
具体的な例でいうと、PostgreSQLのクエリ発行時にprint()でSQLをデバッグ出力していたのが、そのまま起動させれば表示されるのにgulp経由で実行させると全く表示されませんでした(かなりたくさん出力がたまると表示されます)。
最初は、gulp側を疑っていろいろ修正などしていたのですが、たくさん出力したら出ることがあるというのがわかり、「これひょっとしてprint()で勝手にバッファリングされたのがflushされていないんじゃ!?」と・・調べたところビンゴでしたw
これは、上記のようにfflushを実行するとフラッシュされます。
Kituraの関連ライブラリ HeliumLogger のログレベル設定を可能にするように勝手に拡張した私の LithiumLogger にはこのフラッシュ処理を入れています。
NSURLSession系が使えない
これも意外と痛いところで、再びappleのswift-corelibs-foundationを見てみますと、そこにImplementation StatusというのがありFoundationのクラスのうちどこまで実装されているのかが書かれています。
それによると・・・
URL: Networking primitives.
The classes in this group provide functionality for manipulating URLs and paths via a common model object. The group also has classes for creating and receiving network connections.
NSURL is mostly implemented.
NSURLSession and related classes are not yet implemented.
Note: NSURLConnection is deprecated API and not present in this version of Foundation.
NSURLSession関連のクラスはまだ未実装です、とあります。。
ということは、NSURL系のクラスで通信処理を書けないってことです。
ちょっとしたHTTPのクライアントが書きたかったので困りました。いろいろライブラリを調べてみましたが、NSURLSessionをラップしたものがほとんど。
他にもPure Swiftなものもあったんですが、SwiftFoundationを使っていたりしてちょっと使いづらかったので見送り。。
ここで、Kituraのソースをよく見ていくと、Kitura-net内にClientRequestというクラスが!!
どうやら、cURLをラップしてHTTPのリクエストを発行できるクラスのようですが、いまいちこのままだと使いにくい。
・・・ので、HttpClientクラスを作りました!
Kitura Extensionというのをつくってみました | フリップフラップ
上記の記事で紹介した、https://github.com/d-abe/Kitura-extension に追加しています。
使い方は、
のような感じに.header()と.post()または.get()をチェインする形です。最低限の機能しかないですがとりあえずちょっとしたAPIを呼び出すときとかには使えそうです。
注意点として、なぜかSSLに繋がりません。。Kitura-netのClientRequestを使っている関係でcURLのset_optとかが出来ないのでなかなか辛い・・・。最悪、ClientRequestを使うのをやめる形にするしかないかもしれません(誰か作ってくださいw)。
おわりに
このように、Foundationフレームワークの互換クラスがまだまだ未実装が多いですね。Macで書いていた気分で作ってると、「動かん!!」ってことが多発するので注意しましょうw
他にも困ったことあった気がしますが、まずはこれくらいでw