2011年11月23日水曜日

UISearchBarに画像を設定する

UISearchBarに画像を設定するには、UISearchBarBackgroundビューを入れ替えてやります。


// searchBarはUISearchBarのインスタンス
for (UIView *v in searchBar.subviews) {
if ([NSStringFromClass(v.class) isEqualToString:@"UISearchBarBackground"]) {
[v removeFromSuperview];
}
}
UIImage *img = [UIImage imageNamed:@"custom_searchbar"];
UIImageView *iv = [[UIImageView alloc] initWithImage:img];
[searchBar insertSubview:iv atIndex:0];
[iv release];


1.UISearchBarのサブビューからUISearchBarBackgroundを探し、サーチバーから削除します。
2.UISearchBarBackgroundが合った場所にUIImageViewを挿入すれば画像が表示されるようになります。
  (custom_searchbarは背景に使用する画像ファイル名です。)

2011年7月12日火曜日

UILocalNotification

UILocalNotificationは、アプリケーションが終了した状態でも指定時間になったらメッセージを表示する等の動作を行わせることができる機能です。


// ローカル通知を作成
UILocalNotification *ln = [[UILocalNotification alloc] init];

NSDate *dt;
dt = [NSDate dateWithTimeIntervalSinceNow:60]; // 60秒後に表示

// 通知時刻を設定
[ln setFireDate:dt];

// タイムゾーンを設定
[ln setTimeZone:[NSTimeZone localTimeZone]];

// メッセージを設定
[ln setAlertBody:@"起きて"];

// サウンド設定
[ln setSoundName:UILocalNotificationDefaultSoundName];

// ボタンタイトルの設定
[ln setAlertAction:@"Open"];

// ローカル通知を登録
[[UIApplication sharedApplication] scheduleLocalNotification:ln];

[ln release];

上記例の処理をアプリに行わせて終了させると、アプリが動作していなくても60秒後に「起きて」というメッセージが表示されるようになります。

サウンド設定にはサウンドファイル名を拡張子付きで指定しますが、再生時間が30秒未満、かつ以下の形式でないと無効となり、システムのデフォルトサウンドが再生されてしまうので注意が必要です。

●リニアPCM
● MA4(IMA/ADPCM)
● µLaw
● aLaw

上記ファイルはaiff, caf, wavのファイルです。

また、applicationIconBadgeNumberプロパティに任意の数字を指定することで、メールアプリなどでよく見られるようなバッヂが表示されるようになります。



2011年7月7日木曜日

特殊フォルダのパスを取得する

ドキュメントフォルダなどのパスの一覧を取得するには、NSSearchPathForDirectoriesInDomain関数を使用します。


NSArray * NSSearchPathForDirectoriesInDomains (
   NSSearchPathDirectory directory,
   NSSearchPathDomainMask domainMask,
   BOOL expandTilde
);


NSSearchPathDirectoryは、取得するパスの種類を指定します。
定数内容
NSApplicationDirectoryアプリケーションディレクトリ
(/Applications)
NSDemoApplicationDirectoryデモバージョンアプリケーション
ディレクトリ
(/Demos)
NSDeveloperApplicationDirectory開発用アプリケーションディレクトリ
(/Developer/Applications)
NSAdminApplicationDirectoryシステムとネットワーク管理者用
アプリケーションディレクトリ
(/Administration)
NSLibraryDirectoryライブラリディレクトリ
NSDeveloperDirectory開発ツールディレクトリ(/Developer)
NSUserDirectoryユーザディレクトリ(/Users)
NSDocumentationDirectoryドキュメンテーションディレクトリ
(/Library/Documentation)
NSDocumentDirectoryドキュメントディレクトリ
NSCoreServiceDirectoryコアサービスディレクトリ
(/System/Libary/CoreServices)
NSAutosavedInformationDirectory自動保存ディレクトリ
(~/Library/Autosave Information)
NSDesktopDirectoryデスクトップ
NSCachesDirectoryキャッシュディレクトリ
(Library/Caches)
NSApplicationSupportDirectoryアプリケーションサポート
ディレクトリ
(Library/Application Support)
NSDownloadsDirectoryダウンロードディレクトリ
NSInputMethodsDirectoryインプットメソッドディレクトリ
(Library/Input Methods)
NSMoviesDirectoryムービーディレクトリ(~/Movies)
NSMusicDirectoryミュージックディレクトリ(~/Musics)
NSPicturesDirectoryピクチャディレクトリ(~/Picture)
NSPrinterDescriptionDirectoryプリンタ情報ディレクトリ
(Library/Printers/PPDs)
NSSharedPublicDirectoryパブリックディレクトリ(~/Public)
NSPreferencePanesDirectoryプリファレンスペインディレクトリ
(~/PreferencePanes)
NSItemReplacementDirectory「NSFileManager」クラスの
「URLForDirectory:inDomain
:appropriateForURL:create:error:」
メソッドと組み合わせて使用する定数
NSAllApplicationsDirectory全アプリケーションディレクトリ
NSAllLibrariesDirectory全ライブラリディレクトリ


NSSearchPathDomainMaskは、取得するパスの範囲を指定します。
定数内容
NSUserDomainMaskユーザーのホームディレクトリ
NSLocalDomainMaskローカルマシン内
NSNetworkDomainMaskネットワーク内(/Network等)
NSSystemDomainMaskシステム内(/System)
NSAllDomainsMask全てのドメイン


expandTildeは、パスが長い場合にチルダをフルパスにするかを指定します。

NSString文字の配列がNSArrayに返却されます。

アプリで作成したドキュメントをMacと共有できるようにする

iPhoneアプリで作成したドキュメントをMacと共有するには、アプリのInfo.plistファイルを編集します。

ビルド設定の「Info」タグに行を追加し、「Application supports iTunes file sharing」 を追加し、タイプをBOOL型にしてYESにします。

これでiTunesのAppタグからアプリのドキュメントを共有できるようになります。

2011年7月5日火曜日

codesign failed

アップルのデベロッパー登録は1年毎に更新する必要がありますが、この時アップルの説明書の通りに更新しても、いざ新しくビルドを行おうとする時に以下のエラーが出てハマる場合があります。


iPhone Developer: ・・・・・・・・: ambiguous (matches "iPhone Developer: ・・・・・・・・・" in /Library/Keychains/System.keychain and "iPhone Developer: ・・・・・・・・・" in /Users/・・・・・/Library/Keychains/login.keychain)
Command /usr/bin/codesign failed with exit code 1

・・・の部分は開発者ごとに異なります。

この原因はキーチェインに以前登録した古い開発者用の証明書が残っていて、「証明書ユーティリティが新しいのと古いのとどっちを使っていいのか分からない」のが原因みたいです。
この場合、 【アプリケーション】→【ユーティリティ】にあるキーチェーンアクセスを起動してみると、☓印がついた証明書(期限切れの証明書)があると思うので、削除します。

☓印がついた証明書が見えない場合もあり(私はこれでハマりました)、この場合は検索ボックスで「iphone」と検索すると表示されるようになります。


【追記】
xcode4.0.1を使っている時にエラーが出る場合もあります。
この場合、xcode4.1がひっそりとリリースされていて、をれを使えば直る場合があります。
バージョン4以降は【product】→【edit scheme】でArchiveのBuild ActionをDistributionに変えておくのも忘れないようにしましょう。

【更に追記】
同じcodesignエラーですが、エラーの内容が以下の様になる場合があります。

Code sign error: The identity "iPhone Developer" doesn't match any valid certificate / private key pair in the default keychain.

これはキーチェインがデフォルトになっていないからだそうです。
【アプリケーション】→【ユーティリティ】でキーチェインアクセスを起動し、左上の窓からログインを右クリック。【キーチェーン”ログイン”をデフォルトにする】を選択するとエラーが出なくなります。

2011年6月4日土曜日

実機とシミュレータで挙動を変える

ごくまれにですが、実機では動くのにシミュレータでは動かない命令があります。

例えば、iAd広告を表示する時、ADBannerViewのrequiredContentSizeIdentifiersプロパティを設定しようとすると何故かシミュレータでは動きません。

このような場合等に実機とシミュレータで挙動を切り替える必要が出てきますが、シミュレータ上だけで有効になるデファイン値が用意されています。


#ifndef TARGET_IPHONE_SIMULATOR


#endif

#ifndefで囲んだ部分は、シミュレータ用のビルドではビルドされません。

2011年4月18日月曜日

Subviewを最前面・再背面に移動する

特定のSubviewを最前面に移動する場合、bringSubviewToFrontメソッドを使用します。
逆に、再背面に移動したい場合、sendSubviewToBackメソッドを使用します。


[self.view bringSubviewToFront:最前面に移動したいView];
[self.view sendSubviewToBack:最背面に移動したいView]

2011年3月25日金曜日

GameKitで小数を送信する

GameKitでスコアやランキングデータを送信する時、Appleのドキュメントでは整数(int64)のデータを送信する方法しか載っていないので、タイムなどの小数(45.67秒等)を送信したい場合は一瞬戸惑います。

小数を送信する場合、NSNumberクラスを使用します。
NSNumberクラスはBoolやdouble,Int型などのprimitive型をオブジェクトにしたい場合に使用する便利なクラスです。


-(void)reportScores:(double)score forCategory:(NSString*)category
{
scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
NSNumber *numScore = [NSNumber numberWithDouble:round(score * 100)];
scoreReporter.value = numScore.intValue;
[scoreReporter reportScoreWithCompletionHandler:^(NSError* error) {
if (error != nil) {
// エラー処理
return;
}
}];
}


Appleのドキュメントに載っているスコア送信例を、double型を送信するように変更してあります。
上の例では、少数以下2桁を送信する例です。
引数のdouble型scoreを整数にしたいので100倍してNSNumber型のオブジェクトにします。
その後、そのint値(64ビット値)をGKScoreオブジェクトに設定しています。
勿論、iTunesでリーダーボードのスコア設定をDecimal小数2桁等、小数を扱うように設定しておく必要はあります。

後はAppleドキュメントに載っている様にランキング受信処理でGKScoreのformattedValueプロパティを参照すれば、iTunesで設定したフォーマットでNSString文字列が取得できます。

2011年3月2日水曜日

IOS4以降のアニメーション

IOS4以降のアニメーションは、[UIView animateWithDulation:delay:options:animations:completion:]を使います。IOS4以降でも従来のアニメーションは行えるようですが、非推奨となってしまったようです。
もっと簡易的に使えるメソッドもありますが、これだけ覚えておけば事足りるかもしれません。


[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
button.alpha = 0.0; // UIButtonインスタンスを徐々に透明に
}
completion:^(BOOL finished){
button.alpha = 1.0f; // buttonを現す
}];


第一引数はアニメーションにかける時間を指定します。上記例では0.5秒間でボタンを徐々に透明にしていきます。
delayはアニメーションを開始する時間を指定します。上記例では0なので即時アニメーション開始です。
optionsはアニメーションの動作のオプションです。上記例ではEaseOutで徐々に速度を落としてアニメーションをさせています。
animationsが実際のアニメーションの指定です。
completionはアニメーションが終了した時に呼び出される処理です。上記例では徐々に透明になったボタンの姿を再度現すようにしています。

2011年2月19日土曜日

プロビジョニングプロファイル

プロビジョニング等セキュリティ関連の情報をなんとなくまとめてみました。

ID/プロファイル内容
Bundle IDアプリケーション固有のID。アプリケーション1つに1個。(例:com.apple.iTunes)
App ID開発者がアプリケーションに「Push Notification」「in App Purchase」「Game Center」等へのアクセスを許可・禁止設定する為の挙動を管理するID。
キーチェインでのアクセス識別子となり、それぞれのアプリケーションの挙動を制御する。
アプリケーションの「挙動」について1つ付けられるIDの為、複数アプリケーションをまとめて指定できるワイルドカード指定が認められている。(例:com.apple.*)
ただし、GameCenter等のサービスを許可する時はワイルドカード指定は使えない。つまり各アプリケーションに1個のApp IDを付けなければならない。
プロビジョニングプロファイルデバイスにインストールされて、実行時に正規のルートからインストールされたか確認するための情報を保持するファイル。(App ID/デバイスID/開発者IDを保持)

2011年2月4日金曜日

メモリリークしない為に その1

NSMutableArrayやNSArrayをautorelease以外でメモリ確保した場合、配列を解放しても要素の解放処理が呼び出されるわけではありません。


ar1 = [[NSMutableArray alloc] initWithObjects:@"TEST1", @"TEST2", @"TEST3", nil];
ar2 = [[NSMutableArray alloc] initWithObjects:[SomeClass alloc]
, [SomeClass alloc]
, [SomeClass alloc], nil];

arrays = [[NSArray alloc] initWithObjects:ar1, ar2, nil];



[arrays release]; // ar1 / ar2 とSomeClassがメモリリーク


上記例では、「arrays」の解放しか行っていないので、「ar1」「ar2」「SomeClass」が全てメモリリークとなります。
「TEST1」「TEST2」「TEST3」の文字列はautoreleaseされるので解放の必要はありません。

要素を全て解放すればメモリリークしなくなります。

[ar1 release]; // ar1を解放
// ar2の要素を解放
    for (int i = 0; i < ar2.count; i++) {
    SomeClass* tmp = [ar2 objectAtIndex:i];
    [tmp release];
 }
[ar2 release]; // ar2を解放 [arrays release]; // arraysを解放

2011年1月18日火曜日

UINavigationBar

UINavigationBarをUINavigationControllerではなく、UIViewController等に独自に実装する場合、以下のようにします。


// ナビゲーションバーを生成
UINavigationBar* navBarTop = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
navBarTop.alpha = 0.7f;

// ナビゲーションアイテムを生成
UINavigationItem* title = [[UINavigationItem alloc] initWithTitle:@"Title"];

// 戻るボタンを生成
UIBarButtonItem* btnItemBack = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStyleBordered target:self action:@selector(clickBack:)];

// ナビゲーションアイテムの右側に戻るボタンを設置
title.rightBarButtonItem = btnItemBack;

// ナビゲーションバーにナビゲーションアイテムを設置
[navBarTop pushNavigationItem:title animated:YES];

// ビューにナビゲーションアイテムを設置
[self.view addSubview:navBarTop];


ナビゲーションアイテムを生成するときにタイトルを設定します。上記では「Title」という文字列を設定しました。これで画面上部に大きな文字で「Title」と表示されます。

また、ナビゲーションアイテムにiPhoneアプリでよく見られる、画面右上と左上に表示されるボタンなどを設置します。
上記では右上に「戻る」ボタンを追加していますが、leftBarButtonItemプロパティに設置すれば、左上にも表示できます。

UIBarButtonItemはカスタマイズ可能で、例えば

// segmentedControlはUISegementedControlのインスタンス
UINavigationItem* title = [[UINavigationItem alloc] initWithCustomView:segmentedControl];

等とすれば、ナビゲーションバーの内部にUISegmentedControlのインスタンスや、その他スライダー等、いろいろと設置することが可能なようです。

最後に「pushNavigationItem」でナビゲーションバーにアイテムを設置します。
「addSubview」を使いそうになりますので注意が必要です。

2011年1月9日日曜日

連続アニメーション

複数のアニメーションを連続して再生させるには、1つのアニメーションの終了を検知し、その後、続きのアニメーションを再生させます。

アニメーションの終了は「setAnimationDidStopSelector:finished:context:」でアニメーションの終了メソッドを登録しておきます。


[UIView beginAnimations:@"Animation1" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)];
// imgViewはUIImageViewのインスタンス
imgView.frame = CGRectMake(100, 200, imgView.frame.size.width, imgView.frame.size.height);
[UIView commitAnimations];



- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context
{
if ([animationID isEqualToString:@"Animation1"]) {
[UIView beginAnimations:@"Animation2" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
imgView.frame = CGRectMake(100, 50, imgView.frame.size.width, imgView.frame.size.height);
[UIView commitAnimations];


上記例では、イメージ(imgView)を1秒間かけて(100, 200)に移動した後、続いて0.5秒間かけて(100, 50)に移動させます。