iOS7対応


アイコンサイズ

iOS7ではアイコンサイズが変更になりました

iPhone 57 → 60
iPhone(Retina) 114 → 120
iPad 72 → 76
iPad(Retina) 144 → 152

アイコンを自動的に生成してくれるサイトが便利です
http://makeappicon.com/

一度既存のアイコンをすべて削除して追加し直しました。

追加したファイルは

TARGETS > General > App Iconsに追加しましょう(Xcode5.1)

または

TARGETS > Info > Icon files (iOS 5)のIcon filesに追加しましょう

※元々あった 「TARGETS > Info > Icon files」(「Icon files (iOS 5)」ではないほう)は削除しないとiTunes Connectにアプリをアップ時にエラーになってしまいました

iOS7でステータスバーを消す方法

iOS7ではinfo.plistの「Status bar is initially hidden」を「YES」にしただけではステータスバーが消えません。
「View controller-based status bar appearance」を「NO」にしましょう。

マイクへのアクセス許可対応

iOS7では、位置情報やフォトライブラリと同様にマイクを使う場合もユーザーのアクセス許可が必要になります。
以下のメソッドでアクセス許可があるか調べられます。
このメソッドはiOS7未満対応のアプリでも実行可能です。

呼び出し側
[HogeUtil isMicAccessEnableWithIsShowAlert:YES
                                    completion:
^(BOOL isMicAccessEnable) {
    // アクセス許可がある場合はisMicAccessEnableがYES
 }];
HogeUtil.h
typedef void (^IsMicAccessEnableWithIsShowAlertBlock)(BOOL isMicAccessEnable);

+ (void)isMicAccessEnableWithIsShowAlert:(BOOL)_isShowAlert
                              completion:(IsMicAccessEnableWithIsShowAlertBlock)_completion;
HogeUtil.m
+ (void)isMicAccessEnableWithIsShowAlert:(BOOL)_isShowAlert
                              completion:(IsMicAccessEnableWithIsShowAlertBlock)_completion
{
//    // メソッドの存在チェック。存在しない場合はiOS7未満なのでYESを返す なぜか動作しなかった
//    if (![AVCaptureDevice instancesRespondToSelector:@selector(authorizationStatusForMediaType:)]) {
//        return YES;
//    }

    IsMicAccessEnableWithIsShowAlertBlock completion = [_completion copy];

    // iOS7.0未満
    NSString *iOsVersion = [[UIDevice currentDevice] systemVersion];
    NSLog(@"iOsVersion = %@", iOsVersion);
    if ( [iOsVersion compare:@"7.0" options:NSNumericSearch] == NSOrderedAscending ) {
        completion(YES);
        return;
    }

    // このアプリマイクへの認証状態を取得する
    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];

    switch (status) {
        case AVAuthorizationStatusAuthorized: // マイクへのアクセスが許可されている
            completion(YES);
            break;
        case AVAuthorizationStatusNotDetermined: // マイクへのアクセスを許可するか選択されていない
        {
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
                                     completionHandler:
             ^(BOOL granted) {
                 // メインスレッド
                 dispatch_sync(dispatch_get_main_queue(), ^{
                     if(granted){
                         //許可完了
                         completion(YES);
                     } else {
                         //許可されなかった
                         completion(NO);

                         UIAlertView *alertView = [[UIAlertView alloc]
                                                   initWithTitle:@"エラー"
                                                   message:@"マイクへのアクセスが許可されていません。\n設定 > プライバシー > マイクで許可してください。"
                                                   delegate:nil
                                                   cancelButtonTitle:@"OK"
                                                   otherButtonTitles:nil];
                         [alertView show];
                     }
                 });
             }];

        }
            break;
        case AVAuthorizationStatusRestricted: // 設定 > 一般 > 機能制限で利用が制限されている
        {
            if (_isShowAlert) {
                UIAlertView *alertView = [[UIAlertView alloc]
                                          initWithTitle:@"エラー"
                                          message:@"マイクへのアクセスが許可されていません。\n設定 > 一般 > 機能制限で許可してください。"
                                          delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
                [alertView show];
            }
            completion(NO);
        }
            break;
        case AVAuthorizationStatusDenied: // 設定 > プライバシー > で利用が制限されている
        {
            if (_isShowAlert) {
                UIAlertView *alertView = [[UIAlertView alloc]
                                          initWithTitle:@"エラー"
                                          message:@"マイクへのアクセスが許可されていません。\n設定 > プライバシー > マイクで許可してください。"
                                          delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
                [alertView show];
            }
            completion(NO);
        }
            break;

        default:
            break;
    }
}

TableViewのCellの境界線(区切り線)の最初のほうが少し空いているのを元に戻す


    // iOS7.0以上
    NSString *iOsVersion = [[UIDevice currentDevice] systemVersion];
    if ( [iOsVersion compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending ) {
        self.tableView.separatorInset = UIEdgeInsetsZero;
    }

NavigationBar、TabBarへの潜り込み対策

3パターンの対策を紹介します。

対策1. すりガラスのようなエフェクトをやめる

NavigationBarの場合、Translucent NavigationBarからOpaque NavigationBarへ

TabBarの場合、Translucent Tab BarからOpaque Tab Barへ変更します。

対策2. Adjust Scroll View Insetsにチェックを入れ、Under Top Bars、Under Bottom Barsにチェックを入れる

念のため、全てのViewControllerのAdjust Scroll View Insets、Under Top Bars、Under Bottom Barsにチェックを入れます。

対策3. コードで余白を作る (テーブルの場合)

対策1を行いたくなく、対策2でダメだった場合の対策です。
対策2がダメな場合、Viewの順番が関係している可能性が高いです。

参考:
- やはりお前らのiOS7対応は間違っている(解説編)
http://qiita.com/yimajo/items/254c7cebab7864678246

以下のコードでTableViewに余白を作ることができます。
対策2のAdjust Scroll View Insetsのチェックは外しておいたほうがいいです。

- (void)viewDidLoad
{
    [super viewDidLoad];   

    // iOS7デザイン潜り込み対策
    CGRect statusBarViewRect = [[UIApplication sharedApplication] statusBarFrame];
    self.tableView.contentInset = UIEdgeInsetsMake(statusBarViewRect.size.height
                                                   + self.navigationController.navigationBar.frame.size.height,
                                                   0,
                                                   self.tabBarController.tabBar.frame.size.height,
                                                   0);    
}