Swift and CoreMIDI

Swift で CoreMIDI を扱おうとした場合、CoreMIDI で定義されているデータ型が 32-bit でビルドする場合と 64-bit でビルドする場合で異なっていることに注意しなければなりません。この違いは、例えば iOS Simulator で iPhone 5 と iPhone 6 それぞれでビルドしてみると分かります。またソース上のシンボル、例えば MIDIEndpointRef を shift-click した場合に表示される情報や、command-click して表示されるヘッダファイルの内容も異なります。

ちなみにこれは iOS でのお話で、OS X でどうなのかはわかりません。

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?

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 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: の呼び出しを減らしたい気もしますが、
とりあえずうまくいっているので、ひとまずはこれで良しとします。

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 を行っても問題はないようです。

NSTimer と UIScrollView

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

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

この場合は

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

でタイマーを作成し、

-[NSRunLoop addTimer:forMode:]

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

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 アプリの紹介ビデオでも見ていってください。