投稿日:2016年11月20日

0. 環境

[OS] Mac OS X 10.11.6
[IDE] Xcode 8.1
[Swift] 3.0

1. 問題

  • WCSession#sendMessage()を使ってAppleWatchからiPhoneアプリへメッセージを送っても、30秒ほどしないと通知されない。

    • AppleWatch側

      @IBAction func tapButton() {
      
          let message = [ "fromChild": "AppleWatchからのメッセージ" ]
      
          WCSession.default().sendMessage(
                  message
                  , replyHandler: { reply in }
                  , errorHandler: { error in }
          )
      
      }
      
    • iPhone側

      func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
      
          if let watchMessage = message["fromChild"] as? String {
              print(watchMessage)
          }
          else{
              print("error")
          }
      
      }
      

2. 対策

  • replyHandlerを設定するなど、いろいろ情報はあったのですが、結局 sendMessage() を諦め、updateApplicationContext() を使うことにしました。

  • ただ updateApplicationContext() は状態が変わった際に通知するためのメソッドなので、二回目以降の値が変わらないとiPhone側のメソッドが呼び出されません。

    API仕様書には明記されていませんがそのような動きをしています。(「3. 参考ページ」参照)

    ですので、sendMessage() と同じように使いたい場合は、毎回変わる値をダミーとして設定すると実現できます。(多少強引ですが、下記例では時間を設定しています)

    • AppleWatch側

      @IBAction func tapButton() {
      
          let dateFormatter = DateFormatter()
          dateFormatter.locale = Locale(identifier: "ja_JP")
          dateFormatter.timeStyle = .medium
          dateFormatter.dateStyle = .medium
      
          let item: Dictionary<String, String> = [
              "message": "AppleWatchからのメッセージ"
              , "date": dateFormatter.string(from: NSDate() as Date)]
      
          let message = [ "fromChild": item ]
      
          do{
              try WCSession.default().updateApplicationContext(message)
          }catch{
              print(error)
          }
      
      }
      
    • iPhone側

      func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
      
          DispatchQueue.main.async { () -> Void in
              if let watchMessage = applicationContext["fromChild"] as? Dictionary<String, String> {
                  self.label.text = watchMessage["message"]! as String
              }
          }
          return
      
      }
      

3. 参考ページ

投稿日:2016年11月14日

0. 環境

[OS] Mac OS X 10.11.6
[IDE] Xcode 8.1
[Swift] 3.0

1. 問題

  • iPhone & AppleWatchアプリを作成中にSwiftを2.2から3へバージョンアップしたところ、iPhone側で下記のエラーが出るようになりました。

    Type 'ViewController' does not conform to protocol 'WCSessionDelegate'

2. 解決

  • ViewControllerに下記メソッドを追加するとエラーが消えました。

    public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
    }
    
    func sessionDidBecomeInactive(_ session: WCSession) {
    }
    
    func sessionDidDeactivate(_ session: WCSession) {
        session.activate()
    }
    

    下記の仕様書にもこれらのメソッドは必須と書かれています。

    [API Reference] WCSessionDelegate

3. 参考ページ

投稿日:2016年10月07日

0. 環境

[OS] Mac OS X 10.11.4
[Eclipse] Mars.2 Release (4.5.2)

1. 問題

  • 久々にEclipseをさわっていたら、タブをスペースに変換する設定に手間取ったのでメモ。

    (Windowsでもメニュー名を読み替えて頂くと使えます)

    プログラミングで使うインデントに関して、僕はタブ派ですが、職場や最近の流れからしてもスペースを使わざるを得ないでしょう。

2. 解決

  • Eclipseに標準でついている機能が動かなかったので、AnyEditToolsというプラグインを入れました。

    メニューの [ヘルプ]-[Install new software] をクリック。

    [作業対象]に下記を入力。(anyぐらいまで打つと補完されます)

    anyedit - http://andrei.gmxhome.de/eclipse/

    とりあえず最新バージョンのAnyEditToolsにチェック。

    インストール

    [次へ]をクリック。

    途中ライセンスへの同意やセキュリティ警告が出ますが、最後までいくと再起動を求められるのでそのままOKをクリックします。

    起動後、Eclipse上で任意のファイルにタブを入力し、保存したタイミングでスペースに置換されます。

    変わらない場合や細かい設定をしたい場合は下記の設定画面から行って下さい。

    メニューの [Eclipse]-[環境設定] をクリック。

    [一般]-[エディタ]-[AnyEdit Tools]

    設定

    Eclipseでマークダウンを書く人は[Remove trailing whitespace]のチェックを外しておいたほうがいいかもしれません。

    ファイルフィルタ(上記の[Add Filter])で拡張子mdを除外したり、プロジェクトごとに設定(*1)を変えることもできます。

    (*1)プロジェクトごとの設定

    • プロジェクト・エクスプローラーの該当プロジェクトを右クリック。
    • [プロパティ]-[AnyEdit Tools] をクリック。
    • [Enable project specific settings]にチェックを入れる。

投稿日:2016年10月05日

0. 環境

[OS] Mac OS X 10.11.4
[Java] 1.8.0

1. 問題

  • 久々にJavaで実装する機会がありました。標準ライブラリのjava.net.URLクラスは、URLとして解釈できない文字列を渡すと例外が投げられるので扱いずらいですね。

    // IllegalArgumentException が発生。
    url = URL.create("不正なURL");
    

    うーん、最初、RFCを見て「URLとして許可されている文字列だけ渡す」という処理を入れようか迷いました。

    が、一から組むのも骨が折れるなあ~と思って、困った時のApache Commonsを探してみたら、しめしめApache Commons ValidatorにUrlValidatorクラスというのがありました。

    早速このクラスをimportして使おうと思ったら、下記の警告が出てしまいました。

    型 UrlValidator は使用すべきではありません

2. 解決

  • 調べてみたところ、①のパッケージは非推奨で②に変えたら警告も消えました。

    • ①こっちは非推奨

      import org.apache.commons.validator.UrlValidator;

    • ②これを使って!

      import org.apache.commons.validator.routines.UrlValidator;

3. 参考

投稿日:2016年08月20日

0. 環境

[git] 2.7.4 (Apple Git-66)

1. 問題

  • アプリのルートディレクトリに.gitignoreをおいたのですが、git status で見ても追加対象として出てきません。

2. 解決

  • 最初(A)のように書いていたのですが、これだとダメで、[除外設定]→[例外] の順に書かないといけないようです。

    (「. が先頭にあるファイルは除外してね」→「但し .gitignore は例外だよ」)

    • (A) 修正前
    • (B) 修正後
【免責事項】

本ブログのご利用につき、何らかのトラブルや損失・損害等につきましては一切責任を問わないものとします。