2012年12月20日木曜日

アプリReject ! 原因:ReleaseビルドでCould not find a storyboard named...

久しぶりのAppleに申請していたアプリがRejectされた。

iOS6.0.1のiPhone5でテストしたら,起動するとこでクラッシュするとのこと。
(クラッシュログを添付してあったので見てみるが、ろくな情報無し。)

またまたご冗談を・・・と思いつつ、Xcodeからシミュレータで起動する。
問題なし。

provisioningファイルを間違えたかと思ったが、その形跡もなし。

ふと思い立ち、ビルドをリリースの設定にしてシミュレータ起動してみる。

XcodeのProduct→Edit Scheme→Run (アプリ名)→Infoタブ
Build ConfigurationをDebugからReleaseに変更

そうすると・・・
ア、落ちた。

コンソールを確認してみると、StoryBoardファイルが見つからないとか。
Could not find a storyboard named ...

またまたご冗談を・・・・・・

ネットで調べてみると、このバグはたまに起こるらしく、
一旦Storyboardファイルをプロジェクトから削除し、再度追加すると解決するらしい。
というわけで、delete→remove referenceで、ファイル自体は残しておき、
ファインダーから同ファイルをまたドラッグしてプロジェクトに追加。

今度はリリース設定でもシミュレータは落ちなかった。

デバグ設定では大丈夫で、リリース設定では発生するバグとか・・・。
アドホックテストも大丈夫だったのに・・・。

今後はiTunes Connectにアップロードする前に、
毎回リリースビルドで全部テストする必要があるのか・・・

またまたご冗談を・・・・・・・・・。

2012年12月19日水曜日

米長永世棋聖

先日、米長永世棋聖が亡くなった。

米長さんの解説はとてもおもしろく、今でもたまにyoutubeやニコニコ動画で見ている。

特に有名なのが、羽生さんの「伝説の5二銀」だ。
NHK杯で加藤一二三さん相手に羽生さんが放ったこの一手。
そこで米長さんが「おおー、やった!」と叫んだことが一番のファインプレーだった、そうご本人は語られていた。

晩年、現役を退き、将棋連盟の会長に就かれていた。
一方で昨年の調度今ごろ、ボンクラーズという将棋ソフトと対局された。
対局前数ヶ月は、感を取り戻すために詰め将棋をしたり、どうやって攻略するかを検討したりと、ご本人のホームページに書かれていた。
引退したとはいえ、プロ棋士とはこういうものかと感心させられた。

まさに将棋界の大物がいなくなった。
昔、升田幸三や大山康晴が亡くなられた時も、当時の人はこんな気分だったのだろうか。
将来、谷川浩司や羽生善治がいなくなったら、将棋界はどうなってしまうのだろう。
この方たちを超える大物が出てくるのだろうか。

2012年12月18日火曜日

iPhone開発:Game Centerのリーダーボード表示時とかにおかしなアニメーション

自作iPhoneアプリで、Game Centerのリーダーボードとか、アチーブメントのviewを表示しようとしたとき、画面を回転したときのような変な動きをするようになった。

要は、下記のようなコードを通ったとき。
GKAchievementViewController *achievements = [[GKAchievementViewController alloc] init];
if (achievements != nil)
{
    achievements.achievementDelegate = self;
    [self presentViewController: achievements animated: YES completion:nil];
}

で、animatedをNOにしても効果はないし、そういえばNavigationController下にある他のViewに遷移するときも若干おかしい気がする。

そして6時間くらい調べてやっと原因発見。

ゲーム画面のアニメーションで、開始と終了の組み合わせが合っていない箇所があったのだ。

下記コード
for (int i=0;i<5; i++) {
     // アニメーション定義開始

       [UIView beginAnimations:NULL context:nil];
       [UIView setAnimationDelegate:self];
       [UIView setAnimationDuration:0.1f + (0.05 * i)];
       [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
       ・・・
       ・・
       ・

        }
    }
// アニメーションブロック終了
[UIView commitAnimations];

要は、少しずつタイミングをずらしたアニメーションを複数実行したかったわけで、
for文でアニメーションの時間をずらしていた。

そして、なにを考えていたのか(多分コピペして途中にfor文を差し込んだせいだと思うが)アニメーション定義の終了をfor文の外に出していた。

つまり、上記だとアニメーション定義開始を5回やって、定義終了を1回しかやっていないことになる。

しかもここの処理は正常に5回アニメーションされてしまうようだ。
そして気付かないという結果に・・・。

さらにまずいことに、これはアプリ内の他のViewにまで影響してしまうらしく、
原因を探るのにさらなる時間が必要となってしまった。

ということで、以上が原因となり、Viewの切り替えのところで変なアニメーションが発生していた。
定義終了のところをfor文のなかに入れたところGameCenterのviewも正常に表示された。

アニメーション定義の開始と終了は1対1になるように気をつけましょうというお話でした。

2012年12月7日金曜日

iAdが有効にならない

iAdが有効にならない事象がありました。

先月下旬くらいから、新アプリがReady for SaleになってもiAdがTest Adsのまま

一つだけならこちらのミスかなと思ったが、続けざまに3つ連続でなる

iTunes ConnectのContact Usから質問送る(英語)

3つの内一つはバグ修正のため、アップデート申請出していて、それを見て勘違いされて、レビュー待ち状態だからだよと返答される。

返答の一番下に、日本のサポートはこちらとあったので、そっちの方が手っ取り早いかと電話してみる。

こちらでは対応できないので、上のメールに返信して対応してもらってと言われる。

また状況を説明する(英語)

返事するからちょっとまってとメールが返ってくる

翌日、何事もなかったかのように突然3つとも有効になる

さらに翌日、気付いてると思うけど、有効になってるからとメールが来る(英語)

原因は?次申請するとき気をつけることある?と送る(英語)

We appreciate your patience as we worked through a technical issue on our side.
と一行で返事来る。

結果、広告収入5日分削られた。
多分僕は怒ってもいいと思う。

2012年11月9日金曜日

iAd network is temporarily unavailable

iTunes ConnectからiAdにアクセスしようとしたところ,
表題のエラーが表示されました。

また,そのしたに下記文章も。

Permission Denied

You do not have necessary permissions to perform this operation.

「permissionが無い」が気になりますが,
temporarilyとのことなので,多分ほっとけばいいのかな。

11/10追記:
まる二日みれませんでしたが,先ほどアクセスできるようになっていました。

11/11追記
先ほど確認したところ,またエラーになっていました。
どうも不安定な状態のようです。

2012年10月30日火曜日

LandscapeのiPhoneアプリがiOS6のiPadで動かない。その3

本件,Apple Developer Technical Supportに問い合わせしました。


回答:
After looking over the sample, I have concluded that this behavior is a bug.  
Until the application is resized to 2x, all touch events are mistakenly being routed to UIStatusBarAdornmentWindow, a hidden class that is part of the windowing machinery.


バグであると結論されたとのこと。そのままBug Reportに届けてくれとのことなので,そちらに登録しました。

また返答がきしだい更新します。

LandscapeのiPhoneアプリがiOS6のiPadで動かない。
LandscapeのiPhoneアプリがiOS6のiPadで動かない。その2


2013/2/23 追記
上記、まだ返事が来ていませんが、別の対処法を見つけました。


プロジェクトナビゲータのプロジェクト名
TARGETのプロジェクト名
Status BarVisibility
Hide during application launchのチェックを入れる


これで動くようになりました。

2012年10月26日金曜日

LandscapeのiPhoneアプリがiOS6のiPadで動かない。その2

昨日の件,暫定的にでもなんとかできないか考えました。

とりあえず,アプリ開始後の1View目が通ればいけるはずと思い,
最初に表示されるViewの前にひとつ余分にViewをかませてみました。

流れとしてはこんな感じです。
アプリ起動→余分なView(Portrait)→最初のView(Landscape)

余分なViewのViewControllerを継承し,viewDidAppearメソッドのなかで最初のViewを呼び出す感じです。

これにより,アプリ起動時はportraitで起動し,"最初のView"に移った段階でlandscapeに変更されます。

結果としては,正しく反応するようになりました。

ただシミュレータで動かしてみると起動直後にViewが縦と横に遷移しているのがわかり,
見苦しいです。

もっとスマートな方法があるといいのですが・・・。
一応つたない英語でAppleにも問い合わせのメールを送っているので,
良い返事がきたらここに記載します。


10/30 返答が来ました。

2012年10月25日木曜日

LandscapeのiPhoneアプリがiOS6のiPadで動かない。

完全に詰まりました。

今朝あるiPhoneのアプリをリジェクトされました。
テストの結果,最初の画面で全く反応しないことがあるとのこと。

そんなはずは・・・と思いながら,テストの内容にiOS6のiPadが入っていたので,
そういえばこの環境は試していなかったと思い動かしてみると,
確かに全く反応しませんでした。

条件を確かめたところ,
・このアプリを含め,Landscape(横長)表示のアプリで起こる
・iOS6のiPadシミュレータでのみ再現
・iOS6のiPhone,iOS5のiPadでは正常に動く
iOS6のiPadでも,一度x2を押してスクリーンサイズを変えると動く
 (しかもそのあとx1を押して元に戻しても動く)
・アプリをテスト用にportrait設定にすると正常に反応する

環境
・Xcode 4.5.1
・Deployment Target 5.1

一応対応するビューコントローラーには以下のコードを書いています。


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

-(BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
 return UIInterfaceOrientationMaskLandscapeRight;
}



ここから仮説ですが,問題の環境ではボタン等Viewの座標が取得できていないのでは・・・。
x2とかで再度デバイスが座標を計算した結果動くようになったみたいな・・・。

どなたか解決法をご存知でしたらコメント頂けないでしょうか。

10/26追記 暫定対策

2012年10月22日月曜日

エラー: dyld: Library not loaded:  Reason: image not found


AdMob6.2.1に更新している途中で一件エラーが発生しました。

dyld: Library not loaded: /System/Library/Frameworks/AdSupport.framework/AdSupport
  Referenced from: /Users/tanabeyasushi/Library/Application Support/iPhone Simulator/5.1/Applications/(アプリ名)
  Reason: image not found

iPhone 5.1 simulaterで発生。6.0では発生せず。

5.1でAdSupport.frameworkをいれておくと上記エラーになるようです。
対処法としては,このフレームワークをrequiredではなくoptionalにしておけば回避できます。

プロジェクト選択

TARGETSのプロジェクト名

Build Phases

Link Binary with Libraries
AdSupprt.frameworkのRequiredをOptionalに変更

以上です。

2012年10月21日日曜日

AdMob 6.2.1へ更新時のエラー

先日AdMobからメールが届き,バージョン6.2.1でiOS6に対応したのでアップデートしといてとのことだったので,今日試しに一つやってみました。

とりあえず何も考えずに以下のファイルを更新。

GADAdMobExtras.h
GADAdNetworkExtras.h
GADAdSize.h
GADBannerView.h
GADBannerViewDelegate.h
GADInterstitial.h
GADInterstitialDelegate.h
GADRequest.h
GADRequestError.h
libGoogleAdMobAds.a

そして実行!
エラー!


Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_ASIdentifierManager", referenced from:
      objc-class-ref in libGoogleAdMobAds.a(GADIdentifierUtilities.o)
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

まあ,すんなり一発でいくとは思っていなかったので。

いろいろ検索して,最終的には解決法というかAdMobの公式ドキュメントに,
"AdSupport.framework"を追加しておけとの記述がありました。

ということで,プロジェクトのTARGETS→Linked Frameworks and Librariesに上記を追加。

これまでは動いていたので,今まで使用していたバージョンではこのフレームキットは必要なかったと思われます。

これですんなり動きました。

他のも暇があったら全部アップデートしとこうかなと思います。

2012年10月20日土曜日

FMDatabaseで最後にインサートしたレコードの_id取得

iOSでもAndroidでも,データベースはsqliteを使っています。
sqliteは小中規模のデータベース管理ソフトで,主にサーバではなくアプリケーションに組み込む形で使われています。

iPhoneではさらにラッパーとしてFMDatabaseを使用しています。
iOSのsqliteのライブラリはC言語のライブラリで提供されているようで,開発上,文法や型変換がネックになりかねません。
そこを吸収してくれるのがFMDatabaseです。

前置きはこれくらいで,今回は最後にテーブルに書き込んだレコードのidの値を取得する方法を記録しておきます。

FMDatabase *db = [self getDB];
int lastInsertId;
if([db executeUpdate:@"INSERT INTO TABLE1(RECORD1) VALUES(?)", record1]){
        lastInsertId = [db lastInsertRowId];
    }
    else{// 登録に失敗した場合
        NSLog(@"ERROR: %d: %@", [db lastErrorCode], [db lastErrorMessage]);
        [db close];
        return NO;
    }
}
[db close];

*getDBはファイルパスとか指定してdatabaseオブジェクトを取得するメソッドです。

上記のようにしてインサート直後にlastInsertRowIdメソッドでそのレコードのidを取得できます。

気をつけなければならないのは,[db close]後はもう取得できないということです。
後々に使用するのであれば,変数に値をコピーしておく必要があります。

ちなみにsqliteでは,たいていテーブルに_id列という一意の値が入る列を作成します。
上記で取得される値はこの_id列の値と同じです。

今日はこのあたりで。

2012年10月17日水曜日

ブログ表示回数+アプリダウンロード数1000件突破!

おかげさまで一昨日くらいに本ブログの表示回数が1000回を突破してました。

暇つぶしの名前の通り,気付いたこと,まとめておきたいことを暇なときに書いているだけにも関わらず,ご覧になって下さいました皆様,ありがとうございます。

そして,先ほど確認したところ,私が開発したiPhoneアプリの合計ダウンロード数も1000件を突破していました。

内訳は下記の通りです。
・Binary Calculation (9/4〜) 83ダウンロード
・HexadecimalCalculation (10/1〜) 130ダウンロード
・MahjongPoker (10/2〜)   605ダウンロード
・SortSort (10/14〜)  426ダウンロード
(10/17時点)

ダウンロードしていただいた皆様,ありがとうございます。

目標は高く,いつか百万ダウンロードされるアプリをつくれるよう日々頑張ります!

今後もよろしくお願いします。

StoryBoardの警告:Segues initiated directly from ...

現バージョンのXcodeで古いプロジェクトを開いたところ,StoryBoardに下記警告が出ていた。

MainStoryboard.storyboard: warning: Unsupported Configuration: Segues initiated directly from view controllers must have an identifier for use with -[UIViewController performSegueWithIdentifier:sender:]

問題の箇所は,ボタンとかからではなくView Controller(viewの下にあるアイコン)から直接次のビューへsegueをつないでいた箇所で,この場合はsegueにidentifierをつけろとのこと。

対処法は上記の通りで,該当segue(矢印)をクリックし,Attributes inspecterでこのsegueのidentifierを登録する。


ちなみにsegueに登録したidentifierは,画面遷移時に遷移元のView Controllerから遷移先のView Controllerに値を渡す処理とかでそのsegueを特定するのに使ったりする。

2012年10月14日日曜日

App Review Informationの編集結果

3日前,追加されていたApp Review Informationの項目を記入したが,本日その時waiting for review状態だったアプリが無事リリースされた。

どうやら,既にwaiting for review状態で該当個所を編集しても,レビュー待ち時間が延長されることはないようだ。

上記項目を編集すべきか迷っている方,編集しても特に問題ないようです。



あと,日曜日(向こう時間土曜日)でもレビューしていることを初めて知りました。

2012年10月11日木曜日

iTunes ConnectのApp Review Information

iTunes Connectで,Appleの審査待ちのアプリの状態を確認したところ,
ステータスはwaing for reviewのままだが,詳細編集画面が知らない間にエラー状態になっていた。

エラー内容を見ると,App Review項目を埋めて下さいと言う内容で,
実際にApp Review Informationという欄が空欄になっていた。
この項目,確か数日前までは存在していなかったと思う。

今のところApple Developer等からメールで連絡が来た形跡はない。

今ここを編集した場合,レビュー待ち時間がリセットされてしまうのか,
編集しなかった場合,レビュー対象から外れてしまうのか,
どちらにせよ不安にかられたが,結局今レビュー待ちになっている全appで上記項目を記入した。

項目は下記の通り
・First Name
・Last Name
・Email Address
・Phone Number
 *+081から
以下は必須ではないので未記入
・Review Notes
・Demo Account Information

レビュー待ち期間が延長にならないことを祈るばかりである。

10/14 追記:
レビュー待ち時間がリセットされることはないようです。

2012年10月6日土曜日

Xcode 4.5 + AdMobでエラー

Xcodeを4.5にアップデートして,AdMobを使用している既存のプロジェクトを開き,
iOSデバイス(実機やArchive)でRunすると,下記のエラーが発生しました。


ld: file is universal (3 slices) but does not contain a(n) armv7s slice: (workspace location)/(app-name)/libGoogleAdMobAds.a for architecture armv7s
clang: error: linker command failed with exit code 1 (use -v to see invocation)



暫定的な対処方を記録しておきます。

Project Navigatorのプロジェクトをクリック
→「PROJECT」の下のプロジェクト名をクリック
→「Build Setting」タブを開く
→Valid Architecture からarmv7sを取り除き,armv7のみにする。

一応上記の方法で回避できました。
当然ながらarmv7sを取り除くことにより,他の機能に影響が出る場合はこの方法は使えません。
自分の環境では特に削除しても問題なさそうだったので,これでいこうと思います。

2012年10月1日月曜日

AppleからRejectされたアプリ

Appleから2回連続でRejectされたアプリがあり,
レビューによるとボタンが反応せず,まったく操作できないとのことでした。

こちらでは不具合を再現できず,どうしたものかと思っていたところ、
ふとXcodeをアップデートして,最新のiOS6(iPhone5にのっているもの)の
iPhoneシミュレータで起動したところ,再現されました。

最初のリジェクトされたときは1ヶ月前で,まだiPhone5発売前だったにも関わらず,
向こうのかたはそのデバイスでテストをしていたみたいです。

テスト環境を添えてくれるとかしてくれると助かったのですが・・・。

他にもRejectされて原因がよくわからない方,iOS5向けで開発されている方はお気をつけください。

2012年9月30日日曜日

通貨為替変換アプリの作成

某姉さまから,旅先で両替するときに使える通貨換算計算機が欲しいと言われた。
Androidな方なので,久しぶりにandroidのコードを作成。

なるべくリアルタイムに近いレートを使いたいとのことなので,
いいAPIがネットに転がってないか検索したところ,
さすがGoogle先生!パラメータをわたすと計算して返してくれるという優れものを発見。

http://www.google.com/ig/calculator?hl=en&q=1USD=?JPY
のように,httpのgetでパラメータをおくると下記のような結果が返ってくる。
{lhs: "1 U.S. dollar",rhs: "77.9787898 Japanese yen",error: "",icc: true}

これをJSONなりで処理すれば,良い感じに扱えるはず。

ということでコードです。


        String uri = "http://www.google.com/ig/calculator?hl=en&q=1USD=?JPY";
        
        HttpClient httpClient = new DefaultHttpClient();
        HttpParams params = httpClient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, 1000);
        HttpConnectionParams.setSoTimeout(params, 1000);
        
        HttpUriRequest httpRequest = new HttpGet(uri);
        
        HttpResponse httpResponse = null;
        
        try {
            httpResponse = httpClient.execute(httpRequest);
        }
        catch (ClientProtocolException e) {
         //例外処理
         return;
        }
        catch (IOException e){
         //例外処理
         return;
        }
        
        String json = null;
        
        if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
            HttpEntity httpEntity = httpResponse.getEntity();
            try {
                json = EntityUtils.toString(httpEntity);
            }
            catch (ParseException e) {
             //例外処理
             return;
            }
            catch (IOException e) {
             //例外処理
             return;
            }
            finally {
                try {
                    httpEntity.consumeContent();
                }
                catch (IOException e) {
                 //例外処理
                 return;
                }
            }
        }
        
        httpClient.getConnectionManager().shutdown();
        
        String result = "";
        
        try {
         JSONObject rootObject = new JSONObject(json);
         result = rootObject.getString("rhs");
        }
        catch (JSONException e){
         //例外処理
         return;
        }


以上のように,
リクエスト作成→レスポンス受信→JSONオブジェクトに格納→結果用Stringオブジェクトに変換
こんな感じでいけました。

実際につくったアプリも公開していますので,Google PlayでProject Betcheのアプリ,ExchangeATConverterを検索してみてください。

2012年9月22日土曜日

10進数と16進数の変換

Objective-Cでの10進数と16進数の変換について

やりたかったこと:
10進数の整数(要はintとかlongとかの数値)を引数に,16進数のNSString型オブジェクトを返してくれる関数の作成

ロジックとしては,整数を16で割って商と余りを出し続ければいけるはず。

このくらい自分で作ればいいのに,面倒くさがってネットで捜索。
30分かかってC言語のロジック発見。
文字コードを使って、'0' もしくは 'A'に足していくと・・・

C言語の勉強していたときのよくやってたなあと思い出していたところ,
そういえば出力時の%Xがあったといまさら思い出す。

ということで,

NSString *str = [NSString stringWithFormat:@"%X",dInt];

とやって即効で終わりました。

まだまだ修業が足りないと感じました。

2012年9月18日火曜日

iPhoneの横長(LandScape)画面でAdMob表示

AdMobを使用する際,AdMobバナーのサイズ指定で以下のものが選択できる。

GAD_SIZE_120x600
GAD_SIZE_300x250
GAD_SIZE_320x50
GAD_SIZE_468x60
GAD_SIZE_728x90

このうち,320x50がiPhoneの縦画面(Portrait)用のサイズで,あとはiPad用だったり,よくわからないものになる。

そして,「横画面(LandScape)用がないじゃないか!」となるわけで,実際ネットでさがしても皆さんどうしているのかよくわかりませんでした。

ところが昨日,Smart Bannersというものがあることを知りました。
画面サイズに合わせてバナーのサイズを設定できる優れものとのことです。

Smart Bannersについてはこちら

さっそく実装してみました。

// Admobの広告を開始する
- (void) startAdMobAd {
    NSLog(@"startAdMobAdd");
    if (!self.bannerIsVisible2) {
        NSLog(@"startAdMobAdd in");
        
        CGPoint origin;
        if( self.view.frame.size.height < self.view.frame.size.width){
            origin = CGPointMake(0.0,
                                 self.view.frame.size.height -
                                 CGSizeFromGADAdSize(
                                                 kGADAdSizeSmartBannerLandscape).height);
        }else{
            origin = CGPointMake(0.0,
                                 self.view.frame.size.width -
                                 CGSizeFromGADAdSize(
                                                     kGADAdSizeSmartBannerLandscape).height - self.navigationController.navigationBar.frame.size.height);
        }
        self.gAdBannerView = [[GADBannerView alloc]
                              initWithAdSize:kGADAdSizeSmartBannerLandscape
                              origin:origin];
        
        self.gAdBannerView.adUnitID = MY_BANNER_UNIT_ID;
        
        self.gAdBannerView.delegate = self;
        
        self.gAdBannerView.rootViewController = self;
        [self.view addSubview:self.gAdBannerView];
        
        [self.gAdBannerView loadRequest:[GADRequest request]];
        
        self.bannerIsVisible2 = YES;
    }
}


※よくわからないですが,状況によって,viewのheightとwidthが入れ替わっていることがあるので,if文で分岐しています。
※NavigationControllerを使用しているので,originの高さから引いたりしています。(これもなぜか縦横逆転時は引くとおかしくなりました)



やっつけでなんとなくできた感があり,よくわからないこともありますが,動いたからいいかなと。

重要なのは,

initWithAdSize:kGADAdSizeSmartBannerLandscape

のようにしてサイズを指定するところです。

ちなみに縦長だと,

kGADAdSizeSmartBannerPortrait

のようになります。


同じ悩みを持っている方の助けになればと思います。
(他の方法があったりして・・・)

2012年9月13日木曜日

iPhone 5発表!

日本時間本日未明,iPhone 5が発表されました。

処理速度アップに加え薄型・軽量化,さらにiOS6搭載ということです。

iOSのメジャーアップデートということで,すぐに新SDKが発表されることと思いますが,
現状のアプリは改修が必要なのか,さらには今審査中のアプリは差し戻されてしまうのかと心配になってしまいます。


あと個人的には,新iPod Touchが気になってしょうがありません。
(手持ちのiPod Touchが第二世代のものなので)

当時,発売されたばかりのiPod Touch第一世代は外部スピーカもなく,
またまだApp Storeが開設される前だったので標準インストールのアプリしか使用できませんでした。
今では想像もできませんね。

そして翌2008年,ようやくAppストアがオープンし,文字通り数えきれない数のアプリが世に出されてきたわけです。
そんななか第二世代iPod Touchが発売され,「新しい世界」を体験したい衝動が止まらずに購入してしまいました。
毎日のように便利そうなアプリを見つけてはダウンロードしていた気がします。

そこからもうまる4年,今でも現役で使っています。

ただ,そろそろ新しいのを買いたいなと・・・

2012年9月8日土曜日

カウントアップタイマーの実装

iPhoneアプリでのカウントアップタイマーの実装について

ゲーム作成時等,カウントアップタイマーの需要は高いはず。
実際自作のiPhoneゲームにも実装しています。

1.StoryBoardでビューにラベルを貼り付ける

2."ViewController.h"に下記コードを追加


@interface ViewController : UIViewController
{
    NSTimer *_timer;
    NSDate *_stdate;
    NSDate *_now;
    BOOL _timeflg;
}

//timer
@property (weak, nonatomic) IBOutlet UILabel *countUpTimer;


3."ViewController.m"に下記コードを追加


//timer
@synthesize countUpTimer = _countUpTimer;

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:YES];
    
    [self CountUp];
}

//Timer
-(void)CountUp
{
    _timer = [NSTimer scheduledTimerWithTimeInterval:(0.001)
                                              target:self selector:@selector(onTimer:)
                                            userInfo:nil repeats:YES];
    _timeflg = YES;
    _stdate = [[NSDate alloc]init];
}
- (void)onTimer:(NSTimer*)timer {
    if(_timeflg){
        _now = [NSDate date];
        self.countUpTimer.text = [NSString stringWithFormat:@"%.3f",
                                  [_now timeIntervalSinceDate:_stdate]];
    }
}

4.再びStoryBoardで,ビューの下にあるビューコントローラアイコンをCtrlキーを押しながらマウスで押し,そのままLabelまでドラッグする。
すると,下記ポップアップが現れるので,"countUpTimer"をクリックする。 


これでカウントアップされるはずです。


ちなみに,引数scheduledTimerWithTimeIntervalの値0.001は,0.001秒ごとにonTimerメソッドの処理を行うという意味なので,動作が重くなるなど弊害があれば0.01とかにかえたほうが良いかもしれません。

2012年9月6日木曜日

AdMobエラー

先ほどの投稿でAdMobを表示しようとすると,下記エラーが発生した。

 -[GADBannerView private]: unrecognized selector sent to instance 0x8271040 

そして解決方法を下記ブログで発見。

http://tky-albert.blogspot.jp

↓この記事

http://tky-albert.blogspot.jp/2012/08/gadbannerviewsigabrt.html

 --------------------------------------------
Target → Build Settings → Other Linker Flags に"-ObjC -all_load"を入力する。
--------------------------------------------

 感謝!

iAdとAdMobの併用

iPhoneアプリでiAdとAdMobを併用する方法をまとめます。

Xcodeを起動し,
1. プロジェクト名→Targetsを選択→"Linked Frameworks and Libraries"の+ボタンを押し,iAd.framework, AudioToolBox.framework,SystemConfiguration.framework,MessageUI.frameworkを追加する。

2.AdmobのサイトからダウンロードしたAdmob SDKの"GAD〜.h"と"libGoogleAdMobAds.a"ファイルをプロジェクトに加える。

3.下記ソースコードを入力する

・ViewController.h

#import <UIKit/uikit.h>
#import <iAd/iad.h>

#import "GADBannerView.h"


@interface ViewController : UIViewController
{
    ADBannerView *adView;
    BOOL bannerIsVisible; //iAd非表示判定用
    GADBannerView *gAdBannerView;
    BOOL bannerIsVisible2; //Admob非表示判定用
}

@end


・ViewController.m


#import 
#import "ViewController.h"

#define MY_BANNER_UNIT_ID   @"" //AdmobのPublisherIDをここに挿入

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self startiAd];

}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

//iAd,admob実装系

// iAD広告開始
- (void) startiAd {
    
    ADBannerView *banner = [[ADBannerView alloc] initWithFrame:CGRectZero];
    banner.delegate = self;
    /// banner.currentContentSizeIdentifier = ADBannerContentSizeIdentifier320x50;
    adView = banner;
    [self.view addSubview:banner];
    
    //iAdのバナーを画面の外に表示しておく
    [self moveBannerViewOffscreen];
    
}

//iAdのバナーを画面の外に表示する
- (void)moveBannerViewOffscreen{
    CGRect newBannerView = self.view.frame;
    newBannerView.origin.y = self.view.frame.size.height;
    adView.frame = newBannerView;
}

//iAdのバナーを画面の中に表示する
- (void)moveBannerViewOnscreen{
    
    CGRect newBannerView = self.view.frame;
    newBannerView.origin.y = self.view.frame.size.height - adView.frame.size.height;
    
    [UIView beginAnimations:@"BannerViewIntro" context:NULL];
    adView.frame = newBannerView;
    [UIView commitAnimations];
    
}

// iAdの広告を取得したとき
- (void)bannerViewDidLoadAd:(ADBannerView *)banner{
    
    //AdMobの広告を終了する
    [self endAdMobAd];
    
    //iAdのバナーを画面の中に表示する
    [self moveBannerViewOnscreen];
    
}

// iAdの広告が取得できなかったとき
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
    
    ///iAdのバナーを画面の外に表示する
    [self moveBannerViewOffscreen];
    
    //Admobの広告を開始する
    [self startAdMobAd];
    
}

// Admobの広告を開始する
- (void) startAdMobAd {
    
    if (!bannerIsVisible2) {
        gAdBannerView = [[GADBannerView alloc]
                              initWithFrame:CGRectMake(0.0,
                                                       self.view.frame.size.height -
                                                       GAD_SIZE_320x50.height,
                                                       GAD_SIZE_320x50.width,
                                                       GAD_SIZE_320x50.height)];
        
        gAdBannerView.adUnitID = MY_BANNER_UNIT_ID;
        
        gAdBannerView.rootViewController = self;
        [self.view addSubview:gAdBannerView];
        
        // Initiate a generic request to load it with an ad.
        [gAdBannerView loadRequest:[GADRequest request]];
        bannerIsVisible2 = YES;
    }
}

// AdMobの広告を終了する
- (void) endAdMobAd {
    if (bannerIsVisible2) {
        [gAdBannerView removeFromSuperview];
        gAdBannerView.delegate = nil;
        gAdBannerView = nil;
        bannerIsVisible2 = NO;
    }
}

@end

以上のコードで,iAdが取得できた時はiAdが表示され, 取得できなかった場合はAdMobが表示されます。

 また暇があれば,他にもよく使っているコードを載せていきます。

Objective-Cで乱数取得

objective-Cでの乱数の取得方法について。

ゲームなどを作っていると,どうしても乱数が必要になってくる。
その場合,乱数の取得関数"rand"を使用すればいい。

    int randomNumber = rand() % 5;


"% 5"を指定することで,0〜4のランダムな数字を取得できる。

ただし,この関数は一度使用すると値が固定されてしまうので,
例えば以下のように複数の乱数を取得する際に具合が悪い

    int randomNumbers[5];
    for (int i=0;i<=5;i++)
    {
        randomNumbers[i] = rand()%5;
    }

この様な場合では,"arc4random"関数を使用すればいい。
この関数では呼ばれるたびに異なる数値を取得できる。

    int randomNumbers[5];
    for (int i=0;i<=5;i++)
    {
        randomNumbers[i] = arc4random()%5;
    }

とても便利な関数なので,
自分の作成しているアプリではいつも"arc4random"を使用している。

また暇だったらよく使っている関数について書きます。

2012年9月5日水曜日

iPhoneシミュレータでスクリーンショット

作成したアプリをApp Storeに登録する際,スクリーンショットを掲載する必要がある。

その場にiPhone等の実機があればそれで撮ればいいのだけど,
実機がない状態で開発している人もいると思う。

ということで,
そういう場合はiPhoneシミュレータでスクリーンショットを撮ればいいのですが,
案外撮り方をしらない人もいると思うので,(実は自分も)
ショートカットキーを載せておく。


Ctrl + Cmd + C


iPhoneシミュレータの撮りたい画面でこれを押し,
プレビューで

Cmd + n

を押せばスクリーンショットを表示できる。

あとはプレビューの機能で,好きな形式に保存すればいい。

以上,ほぼ自分の備忘録です。


また暇だったら備忘録書きます。

Objective-Cのメソッド呼び出し

最近は違和感がなくなってきたが,
最初はどうもなじめなかったObjective-Cのメソッドの呼び方。

Objective-Cで最初につまずくところだと思うのでまとめてみました。


例えば,NSString型の"str"というインスタンスがあるとする。
NSStringクラスには"length"というメソッドがある。

"str"インスタンスの"length"メソッドの呼び出しは下記の通り。

int len = [str length];


このように,"[オブジェクト メソッド]"で呼ぶ。

ちなみに自クラスのメソッドを呼ぶときは,

[self methodA];


のようになる。




NSStringクラスのsubStringToIndexメソッドは引数が必要だが,
その場合は下記のようになる。

NSString *str2 = [str subStringToIndex : 3];


このように,メソッド名の後ろにコロンと引数を記述する。




引数が複数あるときがすこしややこしく,
2つ目の引数から「ラベル」と呼ばれる引数の説明のようなものが登場する。

例えばNSMutableStringクラスのinsertStringメソッドは,
第一引数としてNSString型のオブジェクトを,第二引数としてNSUInteger型のオブジェクトを指定するが,
このうち第二引数には"atIndex"というラベル名がついている。

NSMutableString型の"mstr"インスタンスからinsertStringメソッドを呼ぶ時は下記の様になる。

[mstr insertString : str atIndex : 3];


このように,第一引数の後ろに「ラベル名 : 引数」の形で記述する。
第三引数以降も同様。




今後も暇だったらObjective-Cでつまずいたところをまとめていきます。

iPhoneアプリ審査通過!


Wating for Reviewのままなかなか進展がなかったiPhoneアプリですが,
本日未明に無事審査を通過し,公開されました!



朝起きてメールチェックしたところ,Appleから3通届いていました。
Appleによる審査は,向こうがアメリカで時差があるため,
こちらでいう深夜に行われるようです。
(そして土日は休みとのことです。)


一応,本日の経過を送られてきたメールの件名でまとめます。

01:02 Your app status is in Review
02:53 Your app status is Processing for App Store
03:27 Your app status is Ready for Sale


in ReviewからAppストアへの登録フェイズまでは2時間くらいのようです。



先月24日にアップロードしてから,1週間半待ちました。
初アプリでしたが,審査に引っかかる箇所は特になかったようで安心しました。



公開したアプリの詳細については,こちらをご覧ください。

2012年9月2日日曜日

Objective-Cについて

iOSの開発では,Objective-Cという言語を使います。

先日まとめたとおり,Objective-Cは「C言語+オブジェクティブ指向」の形でつくられています。

しかし実際に中身をみると,C言語でオブジェクティブ指向を実現するために,ライブラリを大量に追加したものといった感じだそうです。

したがって,C言語のコードは普通に通りますし,Objective-C特有のコードとC言語のコードを混在させることもできます。

実際,XcodeでiPhone用プロジェクトを新規作成すると「main.m」というソースファイルが作成され,その中を見ると下記のような見慣れた関数が書かれています。

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

C言語で最初に覚えるmain関数ですね。
Objective-Cでも,プログラムが開始されて最初に呼ばれるのはmain関数です。

このC言語的な関数の中に,Objective-C特有のメモリの自動管理(@autoreleasepool)だったり,メソッド呼び出し([AppDelegate class])だったりが混在していて面白いですね。



Objective-Cについては,また暇だったら書きます。

iOSアプリ審査

先々週の金曜日(8/24)に作成したiPhoneアプリをiTunes Connectにアップロードした。
その直後にステータスがWaiting for Reviewに移行したが,一週間以上たっても状況変わらず。

初iOSアプリなので,Rejectされてもしょうがないとは思っているが,いずれにせよ早く結果を知りたい。

やはり日々増えていくアプリをすべてレビューするのは無理があるのでは・・・


動きがあったとき,また暇だったら経過を書きます。

2012年9月1日土曜日

公開しているアプリについて

現在公開しているアプリへのリンクを貼っていなかったので。

こちらのブログで紹介しています。

まだ数は少ないですが,どんどん増やしていくのでよろしくお願いします。

また暇があれば。

2012年8月30日木曜日

アンプとDACについて

AV環境をまとめたので,その中のアンプとDACについてまとめます。

まずはプリメインアンプとAVアンプの違いについて
------------------------------------------------------------------

【プリメインアンプ】
 プリメインアンプは,主にステレオ(2ch)で音源を再生するのに使用する。
※音楽CDは,大半がステレオ再生することを想定して録音されている。

たいていはアナログ入力(昔からある黄と赤のケーブル)。
最近はDAC(後述)内蔵でUSB接続等でデジタル入力できるものもある。

プリメインとは・・・
名前の通り,プリアンプとメインアンプを組み合わせたもの。

・プリアンプ→コントロールアンプとも。入力信号の増幅,調整,切り替え等をおこなう。
・メインアンプ→パワーアンプとも。プリアンプからの出力を受けて電力増幅し,スピーカを駆動する。


【AVアンプ】
 AVアンプは,主に多チャンネル(5.1chや7.1ch等)で音源を再生するのに使用する。
※映画はたいてい多チャンネルを想定して録音されている。

最近はHDMI入力が主流(映像データごと入力)
高級品ではアナログマルチ入力もある。

------------------------------------------------------------------

上記の様に,ステレオで音楽を再生するときはプリメインアンプを,
映画を見るときにサラウンドで音を鳴らしたいときはAVアンプを使用するのが一般的です。

また,現在音源としてはCD,DVD,BlueRay,さらにはパソコンに保存している音楽ファイル等ありますが,いずれもデジタルな情報です。
一方,アンプで増幅されてスピーカから出力される情報はアナログ情報です。
そのため,音源からアンプに情報を伝達する過程でデジタルからアナログへの変換をする必要があります。
それを行うのがDAC(digital to analog converter)で,一般的にプレーヤーやパソコンのサウンドカード等に内蔵されています。
ただ,変換の際になるべく周りからのノイズを減らす目的で,独立したDACを使用することもあります。


接続端子別にデジタルかアナログかをまとめます。
------------------------------------------------------------------

【デジタル】
・HDMI,S/PDIF(光デジタル音声端子,同軸デジタル音声端子),USBなど

【アナログ】
・RCA端子の黄色と赤色の物など

------------------------------------------------------------------

こんな感じで,また暇だったら今まで趣味で調べたことをまとめていきます。

2012年8月29日水曜日

AV機器

現在所有しているAV機器について。

まずテレビは昨年春くらいになにも考えずに買ったパナソニックTH-L32X3。
Blue-ray兼HDDレコーダは一緒に買ったDMR-BR585。

↑ここまでは一般的な領域
↓ここからは完全に趣味の領域

まずmarantz製品
 AVアンプ:NR1603
 プリメインアンプ: PM7003
 SACDプレーヤー:SA7003

次にスピーカのB&W製品
  フロントに使用:685
  センター:HTM62

Macから出力用
  DDC:M2TECH Hiface(USB出力)
  DAC:Style-Audio CARAT-SAPPHIRE
  
ってな感じで構成しています。

実際の使い方は以下の通り。

【映画とかみるとき】
DMR-BR585
 ↓ 
(HDMI) 
NR1603→(フロントプリアウト)→PM7003(パワーアンプダイレクト)→685
↓           →HTM62
(HDMI) 
TH-L32X3

【CD,SACDで音楽聞くとき】
SA-7003
PM7003→685

【iMacからiTunesで音楽聞くとき】
iMac
(USB)
Hiface
(同軸)
CARAT-SAPPHIRE
PM7003→685

【今後の展望】
みてお分かりの通り,まだリアスピーカ(とサブウーファー)がありません。
また,SACD-multiが再生できるプレーヤーもありません。
物欲は果てしないのです。

今後も追加があったりして,また暇だったら書きます。

自分のMac歴

主にMacを使っているので。

初めてMacを買ったのは,2006年くらいでした。
今でもサブで使用している,Core DuoのMacBookです。

購入した動機は,以下の2点でした。
①当時デスクトップしかなかったので,大学に持ち運べるようにノートが欲しかった
②ちょうどその年,MacがPowerPCからIntel製のプロセッサに切り替わり,Windowsも動かせるようになった

特に②はとても魅力的でした。
これ一台あれば何でもできる!みたいなわくわく感がありました。

購入後すぐ,今でもVMWare Fusionと双璧をなしているParallels Desktop(最初はParallels workstationだったかな?)が発表されました。
これとVirtualDesktopを合わせて,Fast OS Switchingなんて言葉も一部で流行ったと記憶しています。
その後も仮想マシンとのフォルダ共有や,アプリケーション共有,さらにはCoherence機能等の新機能が追加されていきました。

OSは10.4 Tigerがインストールされていましたが,
そこから10.5 Leopard,10.6 Snow Leopardへのアップグレードで,こちらも新機能が次々と搭載されました。

そして2009年には2台目のMac,24インチのiMacを購入しました。
こちらはいまでもメインで使用しています。

Macbookは10.7 Lionからアップグレード対象外になってしまいましたが,
iMacの方は10.8 Mountain Lionまでアップグレードしています。

その他、2008年にiPod Touchを買い,2010年にiPadを買い,
Magic Mouseが出れば買い,Magic Trackpadが出れば買い・・・
だんだんとApple製品に囲まれていった訳です。

以上が自分のMac歴(Apple歴?)です。

暇だったらまたなんか書きます。

2012年8月28日火曜日

アプリ開発してます。

というわけで。

最近,AndroidとかiPhoneとかのアプリ開発をしているわけです。

それぞれの特徴をまとめておきます。

【アプリケーション動作環境】
 AndroidはGooleが開発しているスマートフォンやタブレット向けのプラットフォーム(OS〜ミドルウェア〜アプリケーションをまとめたパッケージ)です。
その環境の上で動作するアプリケーションを開発しているわけです。

 iPhoneも同様で、iOSと呼ばれるAppleが開発したiPhone,iPod touch,iPad向けのOS上で動作するアプリケーションを開発しています。



【使用する言語】
 Androidアプリケーションは,基本的にJavaです。
JavaはC言語と並んで現在最もシェアの高い言語です。

 iOSアプリケーションでObjective-Cを使います。
Objective-CはもともとMac OS Xで使用されてきた言語で,さらに昔はNeXTstepと呼ばれるOSで使用されていました。
(かのスティーブン・ジョブズの経歴を調べてみると,この辺の歴史がよくわかると思います。)

 JavaもObjecrive-Cも,C言語から派生した言語です。したがって,基本的な文法は共通点が多くあります。
JavaがCやC+を参考にして,オブジェクト指向言語として新たに開発されたのに対し,
Objective-Cは「C + オブジェクト指向」というC言語を拡張した言語として開発されました。



【開発環境】
 Androidアプリケーションの開発は,基本的にEclipseというIDE(統合開発環境)上で行っています。
これにAndroid SDK(ソフトウェア開発キット)とJDK(Java 開発キット)を加えて開発環境としています。

 iOSアプリケーションの開発は,XcodeというMac上で動作するIDEを使用しています。



【マーケット】
 Androidアプリケーションは「Google Play」と呼ばれるGoogleのアプリケーション等の配信サービスを使用します。(以前はAndroid Marketと呼ばれていました。)

 iOSアプリケーションは「App Store」と呼ばれるAppleが運営する配信サービスを使用します。

今日はこの辺で。
また暇だったらそれぞれの開発手順や公開までの道のりを書きます・・・。

ブログ開始

暇つぶし用のブログを作成

多分誰も見ないだろうと思うので,
気楽にやっていく予定。