Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

swift 2つの連続する矢印

swiftでこんなソースが出てきた。-> が2つ連続しているが意味がすぐには分からない。

func multi(val:Int) -> (val:Int) -> Int {
    return { a_val in return a_val * val }
}

省略されている()を書くとこうなる。

func multi(val:Int) -> ((val:Int) -> Int) {
    return { a_val in return a_val * val }
}

これは省略できない方が可読性がいいのではないだろうか。

swift ComparableIndex

swiftのComparableプロトコルはEquatableプロトコルを継承しているので、Comparableと同じことがしたいがEquatableは実装したくないという時に使えない。
その場合、Comparableに相当するプロトコルだけを自分で実装すれば良い。

public protocol ComparableIndex {
    static func LessIndex(_ lhs: Self, _ rhs: Self) -> Bool
}

extension Array where Element : ComparableIndex {
    mutating func sortWithIndex() {
        self.sort(by: { (a, b) in Element.LessIndex(a, b) })
    }
}

これは、Arrayを独自の関数LessIndexで比較してソートする関数を追加するエクステンションである。

PromiseKit4.0 (swift3)を使ってみた 2016年11月

swift3で作ったiOSアプリでサーバーへHTTPリクエストを複数回投げる場合に、 普通に作ると、正常ケース、異常ケースの処理があちこちにばらけて、ソースが汚くなります。

PromiseKitを使ったところ、ソースが短く、処理も追いやすくて素晴らしかったので、メモを残しておきます。

ここでは以下のような処理フローを想定します。

1) ブログ記事のテキストをポストする(request)
2) 生成したブログ記事のIDをjsonで返す(response)
3) 投稿したブログ記事のIDに対して画像を2つポストする(request)
画像ポスト処理は並列に行っても良い。
4) 2つの画像ポストが両方成功したらブログ生成処理正常完了として画面を更新する。
5) いずれかのHTTPの応答が失敗(404エラー等)した場合と、
応答のJSONが意図した内容でなかった場合は、ブログ生成失敗として画面を更新する。

HTTPリスエストを行う部分は、URLSession、Alamofire、APIKit なんでも良いです。

正常応答の場合に渡す情報を持つクラスTと異常応答の場合に渡すエラー情報の2つが必要となります。 クラスTの部分はリクエスト毎に別のクラスを割り当てることができます。 エラー情報はErrorを継承したクラスならなんでも良いですが、ここでは以下のようなenumとしました。 私が使っているHTTPリクエストライブラリは古くてNSErrorをHTTPResponseのエラーとして返すので、 このようにしました。

enum APIError: Error {
    case HTTPResponseError(nserror:NSError)  // 404エラー等
    case JSONParseError // レスポンスJSONのパースに失敗
}

そして、メインの処理は以下のような感じになります。

firstly {
    return Promise<[String:Any]> { fulfill, reject {
        self.sendRequest(r as URLRequest, completion: {(json: Any?, error:NSError?) in
            if let error = error {
                return reject(APIError.HTTPResponseError(nserror: error))
            } else {
                if let json = json as? [String:Any] {
                    return fulfill(json)
                }
            }
            return reject(APIError.JSONParseError)
        })
    }
}.then { json -> Promise<[Bool]> in
    if let blogid:Int = json["id"] as? Int {
        return when(fulfilled: [
            self.postImagePromise(blog:blogid, photo: 1),
            self.postImagePromise(blog:blogid, photo: 2),
        ])
    } else {
        return Promise<[Bool]>(error:APIError.JSONParseError)
    }
}.then { r in
    self.showSuccess()
}.catch { error in
    self.showFail()
}

func postImagePromise(blood:Int, photo:Int) -> Promise<Bool>
{
    このタイミングで処理が成功したことを返す場合は return Promise<Bool>(value:true) とすればよい 

    return Promise<Bool> { fulfill, reject in
        ここでreject(APIError.hoge)またはfulfill(true)をreturnする
    }
}

HTTPでよくある処理を表現するのに適していてだいぶすっきりしています。
JSON周りや、Resultの処理などまだ改良の余地があるソースですが、PromiseKitとは関係ありません。
複数のAPIを投げる場合は、使うとソースのメンテナンスが上がる、むしろ使わないと機能追加やメンテで苦労しそうだと思いました。

digital oceanでipv6を追加したらDNS解決できなくなった話[RESOLVED]

digital oceanに作ったCentOS6のVPSにipv6を追加したところDNS解決できなくなりました。 CentOS7の方は手順通りでうまくいったのですが、CentOS6の方は、

ping google.com

が効きません。

/etc/resolve.conf

にはGoogleのipv6のDNS2つが定義されています。

nameserver 2001:4860:4860::8888
nameserver 2001:4860:4860::8844

ここに、

nameserver 8.8.8.8

を追加してあげると一時的にOKになりますが、rebootすると元に戻ってしまいます。 結局、

/etc/sysconfig/network-scripts/ifcfg-eth0

に以下のようにipv6,ipv4両方のDNSを設定したらOKとなりました。

DNS1=2001:4860:4860::8888
DNS2=8.8.8.8

どうやらDNS3の内容は無視されるようです。

digital oceanの手順書が間違ってんじゃねーか。

以上です。

VisualStudio 2015 VsVimでCtrl+Bが効かない

VisualStudio 2015 に VsVimを入れて使っています。
Ctrl+F(前方スクロール)は動くのですが、Ctrl+Bすると関数のブレークポイント設定機能が動いでしまい、後方スクロールが動きません。
解消するには、「ツール」-「カスタマイズ」-「キーボード」を開き、「デバッグ.関数のブレークポイント」に割り当てられている「Ctrl+B」を削除する。