DerivedData を簡単に消せる Xcode Plugin

懇親会における英会話のプロトコル」を見て try! Swift に行くまでに何か簡単に話せる小ネタがあればなと思って作りました。

Swift を書いているとよくあるのですが、頻繁に中間データが壊れてしまいます。 そのため DerivedData を消すとなおったりします。

消す方法は「Window」->「Project」 を開いて該当するプロジェクトの DerivedData を削除するといったことをしないといけません。 めんどくさいですね。

Clean を実行した時に自動で消してくれたらいいのにと思っていました。

と、いうわけで作りました。

dealforest/Cichlid(シクリッド)

f:id:dealforest:20160301011702p:plain

由来は掃除魚(ベラ・ハゼ・シクリッド・ナマズなど)のベラを採用しました。 Swift で作った Xcode Plugin でコード量も少ないので見れば簡単にわかるかなと思います。

ざっと作った感じですが、意外に便利なのでぜひ使ってみてください。 yidev 第22回勉強会 でこの辺りの話をしようかなと思います。

それでは try! Swift で会いましょう。

isRegisteredForRemoteNotifications が正常に動かなかったときの対処

PUSH 通知が有効/無効をアプリ上で表示(UISwitch等)して有効にしようとした場合にアプリの設定画面に遷移して有効にしてもらう。 といったことを実装することがあるかもしれません。

実装は「[Swift] iOS でプッシュ通知の有効・無効を判定する」を見てもらえれば分かりやすいと思います。

それが意図した通りに動かないケースに遭遇しました。

isRegisteredForRemoteNotifications で有効/無効を確認するのですが、PUSH 通知を許可していないのに true になったり、再インストールした時にダイアログが出ている状態なのに true になったりなどです。

解決方法

registerForRemoteNotifications を呼び出しているしている場所を確認してください。

ドキュメント を見ると application:didRegisterForRemoteNotificationsWithDeviceToken:application:didFailToRegisterForRemoteNotificationsWithError: 以外からの呼び出しは推奨していないようです。

今回はこれが原因でした。 なので 上記の delegate の中から呼び出すようにすればなおりました。

呼び出した場合どうなるか

解決方法で書いたようにちゃんと delegate の中で registerForRemoteNotifications を実行していればこんなことにはならないのですが、何かの役に立つかもしれないので検証した結果を書いておきます。

iOS9.2.1 で下記のコードで検証しました。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    ...
    
    let types: UIUserNotificationType = [ .Badge, .Sound, .Alert ]
    let settings = UIUserNotificationSettings(forTypes: types, categories: nil)
    application.registerUserNotificationSettings(settings)
    print("before \(application. isRegisteredForRemoteNotifications)")
    application.registerForRemoteNotifications()
    print("after \(application. isRegisteredForRemoteNotifications)")
    
    ...
}

検証した限り初回インストールと、再インストールの場合アンインストールした時の通知設定の状況に左右されます。

初回インストール

isRegisteredForRemoteNotifications が正常な値を返す

再インストール

前回のインストールの状況時の PUSH 通知の許可状況に依存します。

アンインストール時に通知を不許可

isRegisteredForRemoteNotifications が正常な値を返す

isRegisteredForRemoteNotifications
before false
after false

アンインストール時に通知を許可

この時が曲者で、初回起動時のみ挙動が変わります。

registerForRemoteNotifications を呼び出したら isRegisteredForRemoteNotificationstrue になります。 そしてダイアログに出ているのに関わらず application:didRegisterForRemoteNotificationsWithDeviceToken: が呼び出され device token が取得できてしまいます。。。

isRegisteredForRemoteNotifications
before false
after true

次回起動時からは通知ダイアログの選択に依存し正常に動作します。

これのタチの悪い所はアンインストール前の通知の有効/無効に依存することです。 状況が不安定になってしまってデバッグ時に困るので delegate の中で registerForRemoteNotifications を呼び出すようしましょう。 (ドキュメントにはそう書いてありますが。。。)

あまり関係ありませんが、いつの間にかアプリを入れなおすと通知のダイアログが毎回出るようになったんですね。 以前は端末の時計を進めて再起動したりしないといけなかったのでお手軽になりましたね。

移転しました

2015年はフリーランスになり色々とあり、あまりブログや発表などでアウトプットができていなかったなと。

諸事情があり前のブログにログインできなくなったこともあり、2016年からは心機一転、移転してやり直すことにしました。(特に深い意味はないです)

SwiftOSS になったのでその辺りや LLDB 周りも追っていこうかなと思っています

といわけで本年もよろしくお願いします。

前のブログ: http://blog.dealforest.net/