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日土曜日

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

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

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

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

また暇があれば。