Home

iPhoneアプリ開発ブログ

CocoaでURLエンコード

NSStringを指定した文字コードでURLエンコードします。

一瞬 stringByAddingPercentEscapesUsingEncoding: のみで事足りそうに思うのですが、それだけだと下記コード中の escapeChars にある文字達が残ってしまいます。

@implementation NSString (URLEncoding)
 
-(NSString *)stringByURLEncoding:(NSStringEncoding)encoding
{
  NSArray *escapeChars = [NSArray arrayWithObjects:
             @";" ,@"/" ,@"?" ,@":"
            ,@"@" ,@"&" ,@"=" ,@"+"
            ,@"$" ,@"," ,@"[" ,@"]"
            ,@"#" ,@"!" ,@"'" ,@"("
            ,@")" ,@"*"
            ,nil];
 
  NSArray *replaceChars = [NSArray arrayWithObjects:
              @"%3B" ,@"%2F" ,@"%3F"
             ,@"%3A" ,@"%40" ,@"%26"
             ,@"%3D" ,@"%2B" ,@"%24"
             ,@"%2C" ,@"%5B" ,@"%5D"
             ,@"%23" ,@"%21" ,@"%27"
             ,@"%28" ,@"%29" ,@"%2A"
             ,nil];
 
  NSMutableString *encodedString = [[[self stringByAddingPercentEscapesUsingEncoding:encoding] mutableCopy] autorelease];
 
  for(int i=0; i<[escapeChars count]; i++) {
    [encodedString replaceOccurrencesOfString:[escapeChars objectAtIndex:i]
                                   withString:[replaceChars objectAtIndex:i]
                                      options:NSLiteralSearch
                                        range:NSMakeRange(0, [encodedString length])];
  }
 
  return [NSString stringWithString: encodedString];
}
 
@end

# なんでもかんでもカテゴリにすればよいというものではないのは分かっているのですが、つい…。

関連する投稿

非公開APIの使い方

実際に使うかどうかはともかくとして、開発者たるもの好奇心と探究心を大切にしなければなりません。というわけで、非公開APIの使い方です(といっても特に難しいことはないのですが)。

1. 使用するAPIの見当をつける

まずは、非公開APIのリストがなくては始まりません。後述するように簡単に自作することもできるのですが、Erica Sadun 女史のサイトに分かりやすくまとまっていますのでこちらを参照するとよいのではないでしょうか。

ericasadun.com (Site Highlights → 2.2 Framework Documentation

Cocoaのくどい(?)メソッド名のおかげで、地道に調べていけばお望みの機能の実装方法の見当をつけることはそれほど難しくないかと思います。

2. フレームワークを読み込む

使用したいクラスが決まったら、そのクラスが含まれるフレームワークを読み込みます。/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/System/Library/PrivateFrameworks 以下にありますね。

3. ヘッダファイルを用意する

続いて、必要なヘッダファイルを用意します。上記のサイトから地道にコピーしてきても良いのですが、行番号が入ってしまっているため面倒です。ここで活躍するのが、各種バイナリファイルから含まれるクラスのヘッダファイルを生成してくれる class-dump-x です。

しかし、今確認してみたところオフィシャルサイトのサーバーに接続できない状態のようです。ファイル自体はこのあたりから取得できそうな感じですが(試していません)、何かあったのでしょうか…。(追記@2009.1.16)無事復活していました。

とにかく、無事アプリケーションファイルを入手できたら、/usr/local/bin あたりのパスが通ったディレクトリに配置して、

> class-dump-x AddressBookUI.framework/AddressBookUI

といったようにすると、AddressBookUIフレームワークに含まれるクラスのヘッダファイルに相当するソースコードがずらずらと表示されます。クラスを限定したい場合には、

> class-dump-x AddressBookUI.framework/AddressBookUI -C [クラス名の正規表現]

こんな感じです。-H オプションをつければ、ヘッダファイルとして吐き出してくれるのでさらに便利です。ちなみに、カテゴリに対しては(クラス名にはヒットせず)カテゴリ名のみが検索対象のようです。

なお、必要なヘッダファイルで使用されているクラスのヘッダファイルも作成して、とやっているとキリがありませんので、直接使用しないクラスは @class で逃げておくとよいでしょう。

4. がんばって試行錯誤する

ここまでくれば、後はあーでもないこーでもないと試行錯誤するだけです。一応お約束なので書いておきますが、ご利用はくれぐれも自己責任でどうぞ。

ちなみに、英語では「undocumented API」と呼ぶのが一般的なようです。

関連する投稿

Provisioning Profile を更新したらビルドエラー

対象デバイスを追加したため Provisioning Profile を更新したところ、下記のエラーが出てビルドに失敗しました。

CodeSign error: a valid provisioning profile is required for product type ‘Application’ in SDK ‘Device - iPhone OS 2.2′

Provisioning Profile を入れ替えた際に、ビルド設定の「コード署名ID」(ターゲット→アプリ名→情報を見る→ビルド→コード署名ID)を更新していなかったのが原因でした。

実は以前も同じ問題で引っかかったのですが、この作業が久しぶりだったためすっかり忘れていました。同じことを繰り返さないように、備忘録として書いておきます。

関連する投稿

Default.pngの使い方

iPhoneアプリの起動時に表示される、Default.png のバリエーションをあげてみます。

ロゴ

もっとも無難な方法ですね。

アプリの初期画面

あくまでもローディング中であることをわかりやすく書いておかないと、タッチしまくっているのに無反応という負のエクスペリエンスを与えてしまうので気をつけましょう。そうなってしまうくらいならば、ただのロゴの方がまだましかと思います。

アプリの初期画面 - UIの中身

UIの良さに定評のある駅探アプリがこの方法です。確かに、ローディング中であることをスマートに表現できる方法ですね。

参考:かつて音楽と呼ばれたもの » Blog Archive » iPhoneアプリ開発 - 身をもって学んだ9の教訓

アプリの初期画面 + 操作説明

個人的にはこの方式が気に入っています。初期画面に簡単な操作説明を書き込んだ画像を表示しておけば、初めて起動した時にも操作に戸惑うことなく使い始めることができます。

ただし、表示される時間が限られているので書き込む内容はギリギリまで単純化する必要があって、うまくやろうとするとなかなか難しいです。

ほかにはどんなパターンが考えられるでしょうか?

関連する投稿

NSDataのMD5メッセージダイジェストを計算する

NSDataクラスにMD5メッセージダイジェストを計算するメソッドを追加してみました。

NSData+Digest.h

#import 
 
@interface NSData (Digest)
 
- (NSString *)MD5DigestString;
 
@end

NSData+Digest.m

#import "NSData+Digest.h"
#import "CommonCrypto/CommonDigest.h"
 
@implementation NSData (Digest)
 
- (NSString *)MD5DigestString
{
  unsigned char digest[CC_MD5_DIGEST_LENGTH];
 
  CC_MD5([self bytes], [self length], digest);
 
  char md5cstring[CC_MD5_DIGEST_LENGTH*2];
 
  for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
    sprintf(md5cstring+i*2, "%02x", digest[i]);
  }
 
  return [NSString stringWithCString:md5string length:CC_MD5_DIGEST_LENGTH*2];
}
 
@end

参考:iPhone で MD5 ハッシュ値を取得には? - 1/4dot Blog

ちなみに、最初はメソッド名を MD5Digest としていたのですが、NSDataを拡張している別のカテゴリに同名のメソッド(NSConcreteDataという非公開クラスのインスタンスとしてMD5メッセージダイジェストを返してきます)が存在するようで、そのせいで少々はまりました…。

同名のメソッドが複数のカテゴリで定義されていた場合、どのカテゴリの定義が有効になるかは保証されていません。

(「詳解 Objective-C 2.0」より)

プライベートメソッドでなく公開メソッドにしておいてくれればよかったのになー、と思ったことは言うまでもありません。

関連する投稿

ソースコードからAPIリファレンスを簡単に表示

Xcodeのエディタ上で、APIリファレンスを引きたいクラス名、メソッド名などをOption+ダブルクリックで該当部分が表示されます(正確には、その文字列を検索した結果のトップの項目が表示される)。

なお、Command+ダブルクリックだとヘッダファイルの該当部分にジャンプします。

知らないとかなりもったいないですね。

関連する投稿

iPhoneシミュレーターの写真アルバムに画像を入れる

  1. 適当な画像ファイルをシミュレータにドラッグ&ドロップ
  2. 画像がSafariで開かれるので、画像の上でマウスボタンを長押し→画像を保存

ただしサイズが小さく、画質が悪くなります。開発にあたっては特に問題ないのですが、なんとかなりませんかね?

(追記)「ただしサイズが小さく、画質が悪くなります」と思ったのですが、UIImagePickerControllerでデータを取り出してみると(オリジナル画像よりは縮小されていますが)実際にはそれなりのサイズと画質で保存されていました(おそらく、iTunes経由で転送したのと同じ状態)。iPhoneのこのあたりの処理は謎ですね…。

関連する投稿

idleTimerDisabled = NO でもスリープしない

[UIApplication sharedApplication].idleTimerDisabled = YES;

とすると自動ロックされない、というTIPSは今や常識なのですが、おかしなことにこのプロパティが NO なのに自動ロックされないという現象に悩むこと小一時間。

デバッグ中はもともと自動ロックされないのですね、というオチでした。

関連する投稿

releaseすべきところでdeallocをすると

iPhoneアプリ開発において、本来releaseするところでdeallocをすると当然ながら実行時にエラーが発生します。ただし、エラーが発生するのはdeallocした場所ではなく値を参照した場所となるので注意が必要です。
以下は今回体験したdeallocとreleaseの間違えでエラーが発生してから原因にたどり着くまでの流れです。

Continue reading

関連する投稿

NSUndoManagerをiPhoneOSで使いたい

詳解Objective-C2.0を見ると、アンドゥ機能を実現するためのクラスNSUndoManagerがFoundation Frameworkに存在すると書いてありました。ところが、XCode上でNSUndoManagerが補完されません。何か設定が必要なのでしょうか。

そこでドキュメントを調べてみるとiPhone OS Technology Overviewに次のような記述が有りました。

Undo management
The NSUndoManager class is not available, and there is no automatic support for undoing operations in iPhone OS.

残念なことに、iPhoneOSにはNSUndoManagerが存在しないようです。

では、iPhone OSでのundoの好ましい実装はどのようになるのかとさらにドキュメントを調べるとCocoa Fundamentals Guideの「What Is A Design Pattern?」に例としてあげられているCommandパターンの中でundo,redoに触れていることが分かりました。CommandパターンはMementoパターンと並んでUndo実装の定石ですので、問題になるのはCommandパターンの実装方法です。

同ドキュメントによると、Commandパターンやタイマー呼び出しなどの為にNSInvocationが用意されていると有ります。NSInvocationは事前にオブジェクト、メッセージ、引数を設定しておき後から実行(Invoke)するためのクラスです。詳しい使い方についてはoomori.com Cocoa Referenceが分かりやすく書かれていました。NSUndoManagerもこのNSInvocationを用いて実装されているようです。

関連する投稿

Home

Search
Feeds
Meta

Return to page top