9月 13 2014

Objective-C でのブロックの宣言

Objective-C でのブロックの宣言の書き方がわかりづらいので、ウェブで探していると気に入ったところがあったので紹介しておきます。Objective-C に限ったことではなく C 由来の言語は宣言文の書き方がわかりづらくなりやすいのが玉にきず。

How Do I Declare A Block in Objective-C?

How Do I Declare A Block in Objective-C?


4月 19 2014

pod install でエラーになる場合の対処法


$ pod install

すると、

[!] Pod::Executable pull --no-rebase --no-commit

A ABContactHelper/0.1/ABContactHelper.podspec

(途中省略)

A zipzap/6.0/zipzap.podspec
Pull is not possible because you have unmerged files.

Please, fix them up in the work tree, and then use 'git add/rm '

as appropriate to mark resolution, or use 'git commit -a'.

のようなエラーとなりました。

以下を参考に、

http://qiita.com/hirayaCM/items/19b8d44c6ff3ab54458d

$ pod repo remove master
Removing spec repo `master`
$ pod setup
Setting up CocoaPods master repo
Setup completed (read-only access)

を行い、再度、

$ pod install

を行うとエラーは発生しなくなりました。


4月 13 2014

stringByReplacingPercentEscapesUsingEncoding: が期待する結果を返さないことがある

パーセントエンコーディングされた ISO-2022-JP 文字列
@"%1B%24B%3CL%3F%3F%1B%28B.PNG"
NSString のメソッド stringByReplacingPercentEscapesUsingEncoding: でデコードしようとすると

NSString *string = @"%1B%24B%3CL%3F%3F%1B%28B.PNG";
NSString *decoded = [string stringByReplacingPercentEscapesUsingEncoding:NSISO2022JPStringEncoding];

@"$B<L??(B.PNG"
が返ってきます。期待している結果は @"写真.PNG" なのですが、どうもうまくデコードしてくれません。

試しに、パーセントエンコーディングされた文字列を
@"%1B%24%42%3C%4C%3F%3F%1B%28%42.PNG"
にしてデコードしてみると、期待通りの結果が返ってきます。

どうやら、%24B, %3CL, %28B がお気に召さないようです。
http://ja.wikipedia.org/wiki/URLエンコード
を読むと、お気に召さない文字列は仕様上間違いではないようですが、上記メソッドでは期待通りにはデコードしてくれません。

仕方がないので、気に入ってもらえるよう、
@"%1B%24B%3CL%3F%3F%1B%28B.PNG"

@"%1B%24%42%3C%4C%3F%3F%1B%28%42.PNG"
に変換して、デコードしてもらうようにします。

とりあえず、以下のコードで変換してみることにしました。

NSString *(^adjustedPercentEscapedString)(NSString *) = ^(NSString *percentEscapedString) {
    NSMutableString *adjustedString = [NSMutableString string];
 
    const char *cString = [percentEscapedString cStringUsingEncoding:NSASCIIStringEncoding];
 
    NSUInteger offsetFromPercent = NSNotFound;
    for (NSUInteger i=0; i<strlen(cString); i++) {
        const char c = cString[i];
        if (c == '%') {
            [adjustedString appendFormat:@"%c", c];
            offsetFromPercent = 0;
        }
        else {
            if (offsetFromPercent != NSNotFound) {
                ++offsetFromPercent;
                if (offsetFromPercent > 2) {
                    [adjustedString appendFormat:@"%%%02X", c];
                    offsetFromPercent = NSNotFound;
                }
                else {
                    [adjustedString appendFormat:@"%c", c];
                }
            }
            else {
                [adjustedString appendFormat:@"%%%02X", c];
            }
        }
    }
 
    return adjustedString;
};
 
NSString *adjustedString = adjustedPercentEscapedString(@"%1B%24B%3CL%3F%3F%1B%28B.PNG");

もう少し、appendFormat: の呼び出しを減らしたい気もしますが、
とりあえずうまくいっているので、ひとまずはこれで良しとします。


1月 18 2014

iOS アプリのための Crashlytics

- Crashlytics 登録からクラッシュログ確認までの 29 ステップ -

アプリはクラッシュしない。それがベストです。しかし現実は様々な理由からクラッシュは発生してしまいます。勘違い、想定外、iOSのバグ、ケアレスミス、エトセトラ、エトセトラ。睡眠時間を削って、休日をつぶして、テストにテストを重ねても、クラッシュの発生はゼロになったと胸を張って言うことはできません。限りなくゼロに近づいているとしか言えないのです。それがプログラマの悲しい現実です。

クラッシュが発生した場合にプログラマにできること。それはクラッシュの原因を素早く特定し、問題をフィックスすること。そのためにはユーザが遭遇したクラッシュの状況を少しでも把握することができる糸口を手に入れることが重要です。その糸口となるのがクラッシュログ。アプリがクラッシュするとクラッシュログが生成されるので、これをなんとか手に入れたい。しかし残念なことに Apple が提供しているサービスではすべてのクラッシュログがプログラマの手に渡ることはありません。

そこで登場するのが Crashlytics。このサービスを使えば失われたクラッシュログがプログラマの手に届きます。(届くはずです ^^;)このサービスは無料で利用できるので、まずは導入して試してみるのが手っ取り早い方法です。ダメならやめればいいのだから。

Crashlytics を利用して、見つかったクラッシュの原因をつぶしていき、少しでも安定したアプリにしていきましょう。

以下に Crashlytics 登録からクラッシュログ確認までのプロセスを説明してあります。2014年1月17日における手順を説明していますので、最新の状況と異なることもあります。29 ステップもありますが、Xcode の使用方法をご存知の方であれば実際の作業にかかる時間はそんなに長くありません。それと作業を実際に行う前に全ステップを一読されることをお勧めします。

  1. http://try.crashlytics.com をブラウザで表示後、メールアドレスを入力し、Try Crashlytics ボタンをクリックします。
  2. crashlytics01

  3. General Info で Name に自分の名前、Company に自分の会社名を入力し、Put me on top! ボタンをクリックします。
  4. crashlytics02

  5. 1. で入力したメールアドレス宛に Crashlytics から You’re on the list to get Crashlytics というサブジェクトのメールが届きます。
  6. crashlytics03

  7. 届いたメールの Wait! Give me priority access! ボタンをクリックしても、You’re on The List と表示されるウェブページが表示されるだけなので、Crashlytics からレスポンスが返ってくるまで、しばらく待っていましょう。
  8. (私の場合)約9時間後に、Crashlytics private access (need reply) というサブジェクトのメールが届きました。
  9. 続いて、Invitation to Join Crashlytics というサブジェクトのメールも届くので、このメールの Sign in ボタンをクリックします。
  10. Crashlytics のウェブページが 1. で入力されたメールアドレスとともに表示されるので、自分の名前と Crashlytics にログインする時に使用したいパスワードを入力し、Create Account をボタンをクリックします。(Crashlytics – Welcome to the Club というサブジェクトのメールが届きます)
  11. crashlytics04

  12. ウェブページが更新され、会社名の入力を促されるので、会社名を入力し、Done ボタンをクリックします。
  13. crashlytics05

  14. 次に、使用したい IDE を選択するページが表示されるので、Xcode をクリックします。
  15. crashlytics06

  16. Mac 用アプリをダウンロードする必要があるので、I agree to the Terms of Service にチェックをつけ、Download ボタンをクリックします。
  17. crashlytics07
    crashlytics08

  18. ダウンロードしたファイル Crashlytics-latest.zip を展開し、Crashlytics アプリをアプリケーションフォルダに移動しておきます。
  19. Crashlytics アプリを起動します。起動後、メニューバーに Crashlytics アイコンが表示されます。
  20. crashlytics09

  21. メニューバーの Crashlytics アイコンをクリックすると、クラッシュログを収集したいアプリの Xcode プロジェクトを指定する画面が表示されるので、ここで Crashlytics に登録したいプロジェクトを選択し、Next ボタンをクリックします。今回は My1stCrashlytics という Crashlytics 確認のためのプロジェクトを作成し、これを選択しました。このプロジェクトは Xcode テンプレートにある Single View Application を選択して作成しています。
  22. crashlytics10
    crashlytics11

  23. 画面が変わり、指定した Xcode プロジェクトの Run Script Build Phase に指定したコマンドを設定するように促されるので、設定を行います。
  24. crashlytics12
    crashlytics13

  25. 設定を終えたら、command-B でプロジェクトをビルドしてください。
  26. ビルドが終わると Crashlytics アプリの画面が変わり、今度は Crashlytics.framework を Xcode プロジェクトに追加するように促されます。画面の赤いツールボックス画像をドラッグし、Xcode プロジェクトの Frameworks へドロップします。
  27. crashlytics14

  28. Crashlytics.framework を追加し終えたら、Crashlytics アプリの画面の Next ボタンをクリックします。
  29. crashlytics15

  30. 次に Crashlytics SDK の初期化コードの記述を行います。Crashlytics アプリの画面にある指示通りに、UIApplicationDelegate の -application:didFinishLaunchingWithOptions: メソッド内にコードを1行挿入し、続いて #import <Crashlytics/Crashlytics.h> も挿入します。
  31. crashlytics16

  32. ソースコードの編集が終わったら、command-R でアプリをビルドし、実行します。(今回は iOS シミュレータ上で実行します)
  33. 今回指定した Xcode プロジェクトにはクラッシュする部分はないので、Crashlytics アプリの画面に Congrats! There are no open issues. と表示されます。
  34. crashlytics17

  35. ここまでくると、My1stCrashlytics was just successfully added というサブジェクトのメールが届きます。もちろんサブジェクトの最初はあなたが指定したプロジェクトのアプリ名になります。
  36. Crashlytics はアプリがクラッシュしたときに有用なサービスですので、アプリがクラッシュしないと意味がありません。アプリをクラッシュさせるには?心配いりません。Crashlytics アプリの画面に Want to force a crash? と表示されていますよね。これをクリックします。
  37. すると、簡単にクラッシュさせる方法が説明されている Web ページがブラウザで表示されるので、そこに記述されている方法を用いて My1stCrashlytics をクラッシュさせることができます。ではやってみましょう。
  38. Xcode に戻って、コードを1行ソースに追加します。追加するコードは、[[Crashlytics sharedInstance] crash]; で、これを画面上の Crash ボタンをタップした時にクラッシュするように仕込んでみます。#import <Crashlytics/Crashlytics.h> を追加するのを忘れないように。
  39. crashlytics18

  40. command-R で実行します。(先ほどと同様 iOS シミュレータ上で実行します)
  41. 実行し、Crash ボタンをタップするとアプリはクラッシュするのですが、Xcode のデバッガが動いているのでクラッシュしたところで実行が止まってしまいます。一旦 Xcode の Stop ボタンをクリックして実行を中止しましょう。
  42. crashlytics19

  43. 今度は My1stCrashlytics アプリを Xcode からではなく iOS シミュレータ上のアイコンをクリックして起動し、Crash ボタンをタップしアプリをクラッシュさせます。
  44. これで、ブラウザから https://www.crashlytics.com/login にログインすると、クラッシュの状況を確認することができます。
  45. crashlytics20
    crashlytics21

  46. また New Issue Discovered in My1stCrashlytics 1.0 というサブジェクトのメールも届くので、メールのチェックをしていればアプリがクラッシュしたかどうかがわかります。数百人のユーザしか持たないアプリでもクラッシュが頻発する下手なアプリをリリースしてしまうと、受信するメール数がとても多くなることが予想されるので、心配な人は Crashlytics 専用のメールアカウントを用意した方が良いかもしれません。(メールを受け取らない設定があるかもしれませんが、まだそこまでは確認していません)

とりあえずここまでで、Crashlytics に登録、アプリにコードを埋め込み、クラッシュレポートの確認までができたと思います。

うまくいきました?
うまくいったのなら、おめでとう。そしておつかれさま。


1月 11 2013

iOS Team Provisioning Profile: * を復活させる方法

iOS Provisioning Portal から iOS Team Provisioning Profile: * を削除してしまった場合、以下の方法で再作成できます。

Xcode の Organizer ウィンドウを開き、ウィンドウ左のペインにリストされているデバイス名を Control-Click します。表示されたポップアップメニューから Add Device to Provisioning Portal を選択します。

あとは Xcode が処理してくれます。
既に Provisioning Portal に登録済みのデバイスに対し、Add Device to Provisioning Portal を行っても問題はないようです。


12月 18 2012

Xcode ビルド設定で利用できる変数の確認

$(SRCROOT) や $(CONFIGURATION) など忘れたときには、
Xcode Build Setting Reference を参照しましょう。

手っ取り早く、

$ xcodebuild -showBuildSettings

で確認できたりもします。


11月 22 2012

NSTimer と UIScrollView

+[NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:]

で作成したタイマーは、UIScrollView のスクロール中に指定時間が経過しても selector を呼び出してくれません。

この場合は

+[NSTimer timerWithTimeInterval:target:selector:userInfo:repeats:]

でタイマーを作成し、

-[NSRunLoop addTimer:forMode:]

で NSRunLoop にタイマーを追加してください。
このとき forMode には NSRunLoopCommonModes を指定します。


11月 10 2012

symbolicatecrash には .crash と .app.dSYM/ と .app/ が必要

ごくまれに、場合によっては頻繁に、どこか別の環境でビルドされた Ad-Hoc ビルドのクラッシュログを見なければならないことがあります。

うまく symbolicatecrash で結果を得るには以下の手順が必要です。
(Ad-Hoc ビルドした .ipa やそのとき生成された .dSYM は入手済みとして話を進めます)

Xcode 4.5.2 の場合、symbolicatecrash は

/Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneOS.platform/Developer/Library/PrivateFrameworks/
DTDeviceKit.framework/Versions/A/Resources

にあります。パスを通すとか、エイリアスを作成するなどしてください。

$ symbolicatecrash MyApp.crash MyApp.app.dSYM/

とすると、

Error: “DEVELOPER_DIR” is not defined at …以下省略

となるので、

DEVELOPER_DIR を設定してあげます。

$ export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer/"

または

% setenv DEVELOPER_DIR /Applications/Xcode.app/Contents/Developer/

再度、

$ symbolicatecrash MyApp.crash MyApp.app.dSYM/

するとクラッシュログの解析結果が出力されるようになりますが、

2   CoreFoundation              0x34279b70 -[__NSArrayM objectAtIndex:] + 160
3   MyApp                   	0x00175470 0xca000 + 702554

といったように、フレームワークのアドレスはシンボル表示されますが、
アプリのアドレスがシンボル表示されません。

これを解決するには、MyApp.app/ が必要です。

$ unzip MyApp.ipa

とすると、Payload/MyApp.app が取り出せますので、
この状態で、

$ symbolicatecrash MyApp.crash MyApp.app.dSYM/

を行います。すると

2   CoreFoundation               0x34279b70 -[__NSArrayM objectAtIndex:] + 160
3   MyApp                        0x00175470 -[MyApp cogitoergosum] (MyApp.m:664)

のような結果が得られ、当初の目的が果たせます。
解凍した MyApp.app は適当な場所にあっても探してくれるようです。

これが探していた情報だったと言う人は
私が作った iOS アプリの紹介ビデオでも見ていってください。


11月 3 2012

XcodeのOrganizerに現れる不要なTEAMSを削除する方法

キーチェーンアクセスの中にある、不要なTEAMSに属する証明書をすべて削除して、Xcodeを再起動すればOK。


8月 23 2012

iPhone 5 以外の「新しい何か」