iOSアプリ開発の逆引き辞典

iPhone/iPadで使えるアプリ開発のTipsをまとめてみました

NSTimerでblocksを処理する

NSTimerのカテゴリを扱ったプロジェクトは沢山ありますが、その中でも「NSTimer-Blocks」が使いやすくて重宝しています。

実際に使う際には、下記のように使用します。下記のサンプルコードはUITableViewのセルをタップして、3秒後にtimerTickedのblocksを処理します。

#import "NSTimer+Blocks.h"

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    void (^timerTicked)() = ^{
        UIAlertView* alert = nil;
        alert = [[UIAlertView alloc] initWithTitle:@"タイマー"
            message:@"満了"
            delegate:nil
            cancelButtonTitle:@"閉じる"
            otherButtonTitles:nil];
        [alert show];
    };

    [NSTimer scheduledTimerWithTimeInterval:3.f 
        block:timerTicked repeats:NO];
}

文字列を表示するサイズを求めるsizeWithFont:メソッドがiOS 7から非推奨になっているのでワーニングが出ないように置き換える

フォントを指定して、文字列が描画されるサイズを求めるのにiOS 6まではsizeWithFont:メソッドsizeWithFont:constrainedToSize:lineBreakMode:メソッドを使っていました。iOS 7ではこれらのメソッドの使用が非推奨になっています。

- (CGSize)sizeWithFont:(UIFont *)font;

- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size;
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode;

ベースSDKがiOS 7.0以上になっていて、これらのメソッドを使用した場合は以下のようなワーニングが表示されます。

'sizeWithFont:' is deprecated: first deprecated in iOS 7.0 - Use -sizeWithAttributes:

該当する箇所が少ない場合はsizeWithAttributes:メソッドboundingRectWithSize:options:attributes:context:メソッドに書き換えていけば良いのですが、多い場合は該当箇所を全て書き換えるのは大変です。

そこでメソッド名のお尻にExを付けたカテゴリNSString (Utilities)を用意して、引数をそのまま吸収させることにします。

@interface NSString (Utilities)

- (CGSize)sizeWithFontEx:(UIFont *)font;
- (CGSize)sizeWithFontEx:(UIFont *)font constrainedToSize:(CGSize)size;
- (CGSize)sizeWithFontEx:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode;

@end

sizeWithFontEx:メソッドでは内部的にsizeWithAttributes:メソッドを使用し、sizeWithFont:constrainedToSize:lineBreakMode:メソッドでは内部的にboundingRectWithSize:options:attributes:attributes:context:メソッドを使用して、指定されたフォントを使った場合に表示される文字列のサイズを計算します。

#import "NSString+Utilities.h"

@implementation NSString (Utilities)

- (CGSize)sizeWithFontEx:(UIFont *)font
{
    NSDictionary *attributes = @{ NSFontAttributeName : font };
    return [self sizeWithAttributes:attributes];
}

- (CGSize)sizeWithFontEx:(UIFont *)font constrainedToSize:(CGSize)size
{
    return [self sizeWithFontEx:font constrainedToSize:size
                  lineBreakMode:NSLineBreakByWordWrapping];
}

- (CGSize)sizeWithFontEx:(UIFont *)font constrainedToSize:(CGSize)size
           lineBreakMode:(NSLineBreakMode)lineBreakMode
{
    NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
    style.lineBreakMode = lineBreakMode;
    style.alignment = NSTextAlignmentLeft;
    
    NSDictionary *attributes = @{
                                 NSFontAttributeName : font,
                                 NSParagraphStyleAttributeName : style
    };
    CGRect rect = [self boundingRectWithSize:size
                                    options:NSStringDrawingUsesLineFragmentOrigin
                                 attributes:attributes
                                    context:nil];
    return rect.size;
}

iAdのバナー広告を表示させる

@interface部分でiAd.hをインポートします。

#import <iAd/iAd.h>

@interface ViewController() <ADBannerViewDelegate> {
}

@property (weak, nonatomic) ADBannerView *adView;

@end

viewDidLoadメソッドでADBannerViewを生成してviewに追加しています。

- (void)viewDidLoad
{
    // 〜〜〜 中略 〜〜〜

    // バナー広告を入れる
    self.adView = [[ADBannerView alloc] init];
    self.adView.delegate = self;

    // 広告が受信できるか分からないのでアルファ値を0にして隠しておく
    self.adView.alpha = 0.f;
    [self.view addSubview:self.adView];
}

ADBannerViewDelegateデリゲートを実装します。optionalなのでデリゲートを用意しなくてもアプリがクラッシュしたりしませんが、先ほどのADBannerViewを表示させるためのコードをbannerViewDidLoadAd:メソッドに入れています。

// iAdの広告の読み込みが完了する前
- (void)bannerViewWillLoadAd:(ADBannerView *)banner
{
    
}

// iAdの広告の読み込みが完了した
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
    self.adView.alpha = 1.f;
}

// iAdからの広告の受信に失敗した
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
    
}

シミュレータでの実行ですのでテスト広告が表示されます。

f:id:ch3cooh393:20140415183440p:plain

UITableViewのセクションインデックスの見た目をカスタマイズする

UITableViewは、決められたフォーマット(UITableViewCell)に基づいてリスト形式でデータを表示するクラスです。

データが多くなりリストが長くなった場合には、SectionIndex(セクションインデックス)を使ってセクション単位でのジャンプをする機能を提供します。

セクションインデックスを表示させる

UITableViewのセクションインデックスを単純に表示させたい場合、UITableViewDataSourceのデリゲートのsectionIndexTitlesForTableView:メソッドを以下のように実装します。

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    return @[ @"2日", @"3日", @"4日", @"5日", @"6日",
              @"7日", @"8日", @"9日", @"●"];
}

iOS 7.0以降では下図のように表示されます。

f:id:ch3cooh393:20140406004437p:plain

セクションインデックスの文字色を変える

[[UITableView appearance] setSectionIndexColor:[UIColor redColor]];

または、

[UITableView appearance].sectionIndexColor = [UIColor redColor];

f:id:ch3cooh393:20140406004451p:plain

セクションインデックスの背景色を変える

[[UITableView appearance] setSectionIndexBackgroundColor:[UIColor purpleColor]];

または、

[UITableView appearance].sectionIndexBackgroundColor = [UIColor purpleColor];

f:id:ch3cooh393:20140406004502p:plain