Technical Column

iOSのアプリケーション開発を行う上での備忘録として少しずつ不定期に書いてきたいと思います。

 

お気づきの事とは思いますが、この「Technical Column」は全てトップページに移行しています。

 

 

10 Responses to 'Technical Column'

  1. FuturesVision says:

    iAd

    気付いている人も居ると思いますが、8月末から日本でもiAdのサービスが始まりました。FuturesVisionのぽけっと定規にも 1.2 から広告を入れさせて頂いています。
    実は 1.1 から iAd 単独の広告を入れていたのですが、その時点では日本でサービスが始まっておらず、殆ど意味がありませんでした。(もちろんUS等でダウンロードして頂いた方々からのアクセスはありました)

    今は#ifdefで実装されていませんが、ソースの中に残っているiAdの実装部分をご紹介します。一応、AppleのReviewも通過したソースです。
    これをRootViewControllerの中で実装し、- (void)viewDidLoad の中で

    [self addBarInit];

    を呼び出してやるだけです。

    -(void)adBarInit {
    CGRect r;
    CGFloat tabBarHeight;
    UIDevice *device;
    NSString *ver;

    bannerIsVisible = NO;
    device = [UIDevice currentDevice];
    ver = [device systemVersion];

    if([ver compare: @”4.0.0″] == NSOrderedAscending) {
    return;
    }

    adView = [[ADBannerView alloc] initWithFrame: CGRectZero];
    adView.alpha = 0.5f;
    adView.delegate = self;
    if([ver compare: @”4.1.9″] == NSOrderedDescending) {
    adView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifierLandscape];
    adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
    }
    else {
    adView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifier480x32];
    adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifier480x32;
    }

    tabBarHeight = 49;

    r = adView.frame;
    r.origin.y = self.view.frame.size.width- tabBarHeight – adView.frame.size.height;

    if([ver compare: @”4.1.9″] == NSOrderedAscending) {
    r.origin.y -= 8;
    }
    adView.frame = r;

    device = nil;
    ver = nil;

    [self.rulerView addSubview: adView];
    [self.rulerView bringSubviewToFront:adView];
    }

    – (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
    if(bannerIsVisible) {
    [UIView beginAnimations:@”animateAdBannerOff” context:nil];

    [UIView commitAnimations];
    bannerIsVisible = NO;
    }
    }

    – (void)bannerViewDidLoadAd:(ADBannerView *)banner {
    if(!bannerIsVisible) {
    if(activeView == nil) {
    activeView = self.rulerView;
    [activeView addSubview: adView];
    [activeView bringSubviewToFront:adView];

    }
    [UIView beginAnimations:@”animateAdBannerOn” context:nil];
    [UIView commitAnimations];
    bannerIsVisible = YES;
    banner.hidden = NO;
    [banner setNeedsDisplay];
    }
    }

    忘却とは恐ろしい物で、コレで全部か?と言われると…な状況ですがご参考にはなると思います。

    サービスが始まったとは言え、まだまだiAdがヒットする確率は低いようです。私もまだ1度しか見た事がありません。
    ですがiAdに限らず広告を入れると、ダウンロードされた自分のアプリがどの程度実際に利用されているのかが分かるので、参考になります。
    ダウンロードされても実際に使って頂かなければ寂しいですもんね。

    最後に、ぽけっと定規は無料のアプリですので、出来ればたまに広告をクリックして頂けると助かります。
    また、有料ではありますが広告無しのぽけっと定規プラスもありますので、よろしければそちらもご利用ください。

    次回はぽけっと定規 1.2で実装したAdWhirlについて書いてみたいと思います。

  2. FuturesVision says:

    UITableViewCellをカスタマイズする(の続き)

    デバイスをローテーとした場合には、UIViewControllerのサブクラスに shouldAutorotateToInterfaceOrientation のメッセージが送られます。


    – (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
    return YES;
    }

    ここでNOを返してしまえば問題ありませんが、YESを返すと画面がローテートします。中には UIInterfaceOrientationPortrait しか対応していないアプリも多いように見えます。iPhoneやiPod Touchを使用していると UIInterfaceOrientationPortrait だけでも十分ですが、iPad(2を含む)ではどちらかというとLandscapeが一般的な気がします。
    特にiPad2ではSmartCoverの関係で UIInterfaceOrientationLandscapeRight が一般的かなぁというのが私の感想です。(全く個人的な感想)

    そこで困るのが、そのViewに表示している各表示項目の配置です。Portraitで一番下に表示していたもの等はLandscapeでは配置をかえてやる必要があります。
    しかし各Viewにはローテートが発生したかどうかは伝わってきません。
    そこで私が取っているのがUIViewの -(void)layoutSubviews の上書きです。
    下記のようにLandscapeかどうかを判断して配置のしなおしをしています。


    -(void)layoutSubviews {
    NSInteger isLandscape;
    UIApplication* app;
    UIInterfaceOrientation orientaion;

    CGRect f;
    CGPoint p;

    if(caloryLabel.text == nil || [caloryLabel.text isEqualToString:@””]) {
    updateButton.enabled = NO;
    }

    app = [UIApplication sharedApplication];
    orientaion = app.statusBarOrientation;
    isLandscape = UIDeviceOrientationIsLandscape(orientaion);

    switch (isLandscape) {
    case YES:
    f = label.frame;
    f.size.width = 480 – 30;
    foodNameLabel.frame = f;
    f = label.frame;

    「これで一安心」
    と思っていたのですが、いくつかの部分で動かなくなってしまった機能がありました。その一つがUITableViewCellをサブクラス化した部分です。
    いつの間にかswipeによるセルの削除などが出来なくなったのです。
    最初は

    – (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    あたりを疑ったのですが、らちがあきません。
    結局たどり着いたのは先ほどの -(void)layoutSubviews です。
    オリジナルのUITableViewCellでも使っていたのですね。
    そこでこのメソッドの最後で

    [super layoutSubviews];

    と追加してやる事で問題は解決しました。

  3. FuturesVision says:

    TableViewCell をカスタマイズする

    UITableViewとその元のUITableViewCellの機能は豊富かつ強力で、殆どの場合にはそのままで使用出来ると思います。しかし表示の仕方をカスタマイズしようとすると限界にが出てきます。
    UITableViewは2次元(sessionを含めると)のテーブルを管理しますが、それぞれのセルの表示を担当しているのがUITableViewCellクラスです。
    これをサブクラス化すれば表示できる項目もカスタマイズ出来ます。
    全てをObjective-Cのソースで書く事も出来ますが、Interface Builderを使わない手はありません。

    まずはUITabeleViewCellのサブクラスを作成します。ここでは単純にTableViewCellクラスとします。
    次にUIViewベースのxibを作成します。
    xcode上でviewを選択肢、クラス名を先ほど作成したTableViewCellに変更します。

    次にUITableViewControllerまたはUITableViewControllerのサブクラスと関係付けてやります。

    このように、File’s OwnerのクラスをUITableViewControllerまたはUITableViewのサブクラスに指定してやります。
    その中には、新しいセルのクラスを IBOulet で定義してやります。


    #import
    #import "TableViewCell.h"

    @interface TableViewController : UITableViewController

    @property (nonatomic, assign) IBOutlet TableViewCell* tableViewCell;

    @end

    このようにInterface Builderを使うとセルとテーブルを関連づけてしまうため、再利用が面倒ですが、コードを書く手間は格段に減ります。

    ではUITableViewの中でどのようにして新しいセルを作ってやるかというと、テンプレートとして作成された以下のメソッドに実装を付け加えてやります。


    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    static NSString *CellIdentifier = @"Cell";

    TableViewCell *cell = (TableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    [[NSBundle mainBundle] loadNibNamed:@"TableViewCell" owner:self options:nil];
    cell = tableViewCell;
    }
    tableViewCell = nil;
    cell.label.text = @"Label";

    return cell;
    }

    面白いのはloadNibNameでロードして来ていますが、返り値がありません。
    これが先ほどIBOutletで指定した場所(TableViewCell* tableViewCell)に自動的に入ってくるわけです。

    さて、上のコードでは
     tableViewCell = nil;
    としているだけですが、メモリーリークは?と思いますが、これはretainではなく、assignで定義されていますので明示的な releaseは要りません。

    基本はコレだけです。
    Interface Builderで作成したUITableViewCellのサブクラスは、当然UIViewクラスのサブクラスですので、そこに貼付けられるものは大概貼付けられます。

    今日はここまで。
    次回は、この方法でセルを作った場合に気付いた事…
    を書いてみようと思います。

  4. iOS5 Veil Out on WWDC says:

    WWDCでiOS5がveil out しましたね。
    「もう他に何を付け加えるの?」と思いましたが色々ありますね。
    ちょっとワクワクです。

    アプリケーション開発側としては、あまりAppleがアプリケーション・レイアには踏み込んでほしくないのですが、面白いですね。

    ユーザーとしてはiMessageやPC Freeなんて良いですね♪

    PS.
    ちょっと101が懐かしい、なう

  5. FuturesVision says:

    ユニバーサル・アプリケーション

    iOSを搭載しているH/Wも2分化し、iPhone(iPod Touch)系とiPad系の二つに分離しました。
    どちらも基本的には同じなのですが、画面サイズが違います。
    では1つのアプリケーションで2つのコードを描かなければいかないかと言えばNOです。
    明らかに違う部分に付いては分岐させなければしょうがありませんが、多くの部分は共有出来ます。

    Interface Builder用のxibファイルの作成は、各プラットフォーム用に作る必要があります。
    その際にはクラスファイルも作成されますが、Interface Builder上で該当部分のクラス名を変更する事が出来ます。その際に、それらを包含するクラスファイルだけを作っておき、Interface Builder (今は実際にはxcode)が作成したクラスの親クラスを別途作成したクラスに統一してしまえば良いのです。

    ボタンやUIViewのサブクラスをInterface Builderで画面に貼付ける際も、その子クラスを予め作っておけばiPhone用のxibファイルでもiPad用のxibでも同じクラス名を指定してやる事で、一つのクラスをメンテナンスしてやれば良い事になります。

    けっこう開発の効率化にはなりますよ。

  6. FuturesVision says:

    iPad2

    本日発売されたiPad2を早速購入してきました。
    iPadが出たときにはあまり興味を示さなかったのですが、なんとなく最近気になりだしたのと、製品開発をする上で実機が無いというのも問題なので購入してみました。
    既にiPadを購入されている方には当たり前のことなのだと思いますが、やはりiPadはiPhoneやiPod Touchの画面が大きくなっただけでは無いという事です。もちろん技術的なスペックでの大きな違いは大きさくらいです。
    しかしこの画面の大きさが、デバイスの用途を大きく変えることに気付きました。
    例えばTwitterのクライアントアプリなら、TLを多く表示出来るだけではアプリとしての魅力を感じません。

    しかし気付いたことは、iPod Touchで今まで使っていたアプリもまだまだiPadへの対応がまだまだだと言う事です。すなわちビジネスチャンスはまだまだあるのでは?という事。

    テスト機とは言え、音楽や写真などのデータも同期させようとなると、それだけに時間が掛かってしまうのは考え物ですね。

    ちなみに購入したのは32GBのホワイトです。
    ついでに白のスマートカバーも購入してしまいました。

  7. FuturesVision says:

    xcode 4

    プロジェクトの途中で開発ツールを変えるっていうのは最悪なようだ。
    今まで使っていた xcode 3.x を途中で xcode 4にバージョンアップしてしまいました。
    この xcode 4。バージョンアップというよりも、別の製品のような気がします。
    Interface Builderも内包してしまい、微妙に使い方が違う。
    フレームワークの追加の仕方も違うし、Destribution バージョンのビルドの使い方も違う。
    今作っているものは、何とかなるとは思いますが、次を作るときには考えてしまいます。

  8. FuturesVision says:

    AVFoundation.frameworkとTARGET_IPHONE_SIMULATOR

    AVFoundation.frameworkがシュミレータで全然対応していないとは思わなかった。
    元々AVFoundation.frameworkはカメラ関係をまとめてiOS4.0以降に整備されたフレームワークなわけだから、シュミレータ上では動かないのだが、逆にカメラが搭載されていない機種でのテストをしようとすると行き詰まってしまう。

    #ifdefでTARGET_IPHONE_SIMULATORを括り、シュミレータ上では邪魔になるクラスなどを省いてみた。とりあえず動作するようになったが、最終的には実機でしかテストを出来ないというのは問題だなぁ…。
    iOS4.3ならシュミレータ上でも動くようなので、最小構成をiOS4.3(最新)にするか?
    それじゃターゲットが非常に限られてしまう。

    #ifdefでバイナリーを分けてしまうのは、開発者としてあまりいい気持ちではないな。

  9. FuturesVision says:

    Required device capabilities

    iPhoneや、iPod Touch、iPadも様々なハードウェア・バージョンが出てきました。
    3G機能(電話)を搭載している機種やカメラを搭載している機種…
    しかしアプリケーションを開発するにあたって、これだけは必須というハードウェア機能を搭載した機種だけを対象とする場合にはそれらを限定しなければなりません。
    その時に便利なのが info.plist の “Required device capabilities”キーワードです。
    ここで設定出来る値はiOS Developer Libraryにあります。
    その他にも便利なキーワードがありますのでご覧下さい。

  10. FuturesVision says:

    アプリケーション名の国際化

    日本で発売されるiPhoneなどは日本語の表示になっていますが、居住地とは別に表示言語を「設定」→「一般設定」→「言語環境」で変更する事が出来ます。もちろん海外で発売されている製品はその国の言語に設定されていると思います。
    もし自分が開発したアプリケーションを海外でも売りたいような場合には国際化が必要です。とりあえずここではホーム画面のアイコンの下に表示されるアプリケーション名を国際化する方法を説明します。

    まず、xcodeで”Resources”フォルダーを右クリックし、「追加」→「新規ファイル…」を選びます。

    ファイル名を”InfoPlist.strings”にして保存すると”Resources”フォルダにファイルが現れます。
    次に”InfoPlist.strings”を右クリックし「情報を見る」をクリックするとウィンドウが表れますので「一般」タブで「ファイルをローカライズする」を選択します。
    最初は”English”しかありませんので”Japanese”を追加します。

    するとxcode上のInfoPlist.stringが日本語用と英語用に分かれますので、その中にそれぞれの言語用に下記のようにアプリケーション名を設定します。

    CFBundleDisplayName=”アプリケーション名”;

Leave a Reply

Your email address will not be published. Required fields are marked *

*

CAPTCHA


WP-SpamFree by Pole Position Marketing