iOSアプリをApp Storeに申請した

仕事ではじめてがっつり触れたiOS開発、最初は色々と戸惑う事もあったけど慣れてくるとObjective-Cでコーディングしているのが妙に楽しくなってきた。

具体的に何がっていうのがちょっと言葉に出来ないのだけど、なんか書いてて気持ちがいい。自分でもよくわからない

 

そんなこんなで学習のつもりで始めたiOSのアプリ開発が最初に思い描いてた機能を実装した辺りから「あれも欲しい」「これも欲しい」と欲が出てきて結局妙にそれっぽいアプリが出来上がってしまった。

このままお蔵入りさせるのも何かなーと思い、いっちょ身銭を切ってApple様に開発者登録してもらいましょうって事でつい最近iOS Developer Programに登録した。

※開発段階は殆ど無料アカウントで開発。これだとシミュレータの動作確認しかできない

 

今はレビュー待ち状態なので、申請まででやった事や思ったことを書いておく

  • 開発用、公開用の証明書の発行
  • 実機転送と動作確認
  • 諸々の画像用意

まず開発用、公開用の証明書の発行。

これはググればいくらでも情報が出てくるだろうけど、個人的にこの作業をやるのはプロジェクトを作ってすぐが良いかなと思った。

私の場合、最初に開発用だけ作成し、公開用をリリース直前で作ったのだが、色々と忘れていて何の設定が必要で何と合わせなくちゃいけない等が全く思い出せず、エラーを大量生産した。

結局開発用、公開用共に最初から作り直す羽目になったので最初からやっておきましょうと思いました。

 

次に実機転送と動作確認。

実機に転送するの自体は面倒だけどそこまで難しくない。ただ実機転送してからが酷かった。

シミュレータはあくまでシミュレータなので完璧に動作するとは思っていなかったのだけど、かなり意図通りに動かない。回転を考慮してframeのサイズや位置を作り直している所とか割とガタガタになる。

とは言えそれはまた実機用に変えてやればいいだけなのだが、如何ともし難いのがメモリ不足。シミュレータ上では快適に動いていたあの娘も実機になった途端不機嫌極まってて即強制終了とかもザラだった。

この辺りは「実装を変える」から「機能を削る/削らない」の判断をしなくちゃいけなくなるので、やっぱり最初から実機で開発が良いよねと思いました。

ケチが服着て歩いてる様な人間なので、無料で続けてたツケは結構大きかったです。

 

最後に画像の用意。

これが本当に時間がかかった。デザイン力皆無なのでアプリを公開するかしないかの大きな壁になっていてかなりの時間を費やしてやっと作れた。

まずはアイコン。App Storeに申請するときには様々なサイズのアイコンが必要になるのだけど、それを一発で作ってくれるのがこれ

1024*1024の画像を作る所からそもそもハードル高いと思うけど、そこを何とか突破すれば後は楽に作ってくれる。

 

次にスクリーンショット。アプリの画面を撮ればいいだけなんだけど、ステータスバーは写ってたら駄目とかいうので切り取ったりした。でもステータスバー写ってるスクリーンショット使ってるアプリ結構あるけど、どうなんだろう。

このスクリーンショットが割と曲者で、iPhoneだけで出す場合、3.5inch用と4inch用の2つを用意しなくちゃいけない。iPadを含めてるならその分も追加。

iPhone4Sしか端末がないので4inchのスクリーンショットは撮れず、3.5inch用のを引き伸ばして使ったりした

 

 

パッと思い出せる苦労したポイントはこんな所。

後はRejectされないのを祈るだけ

画像に何か加工を行った際に向きが勝手に変わってしまう

大雑把な括りになってしまうけれど、かなりハマってしまったので備忘録として残しておきたい。

タイトルの問題は画像に対してCoreImageを使い、エフェクトをかけたり、QuartzCoreを使って回転させたりした時に起こった。

テストで使っていた画像は

  1. iPhoneの壁紙用に作った960*640の画像
  2. iPhone(4S)のカメラで撮った3264*2448の画像

の2種類。1の場合はエフェクト、回転共に全く問題なく動作して安心していたのだが、2の画像でテストした時に思うように行かなくなった。

具体的には

  • CoreImageでエフェクトをかけた場合は90度回転した状態で画像が生成される
  • QuartzCoreで回転させた場合は縦長だった画像がそのまま横に伸ばされてしまったような状態の画像が生成される

とメチャクチャな結果になってしまった。

まず初めに疑ったのは画像のサイズ。大きなサイズを加工しようとしているのでメモリ不足を起こして妙な結果になっているのか?と思ったのだけど、どうもそうじゃないっぽい。

これに気がついたのはCoreImageのエフェクトをかける時にGPUで処理させず、CPUで処理させるようにして画像の大きさについてはクリアしてるであろう状態でも起こってしまったから。となるとCIImageとかで何かOrientationの指定をしないと勝手に向きが変わるのかなと予想して色々調べた。

 

結果、問題はCoreImageでもQuartzCoreでもなく画像そのもの、UIImage(のCGImage)にあった。

通常カメラで撮った写真の向きはUIImageのimageOrientationに保存されているのだけど、CGImageはそれを無視するらしく本問題が引き起こされる。

 

じゃあどうするかというとdrawInRectを使って一度画像を作り直す事で対処した。

drawInRectは写真の向き通りに画像を作ってくれるので

    UIGraphicsBeginImageContext(image.size);
    [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

こんな感じで一度作りなおしてやる。これでこのimageはエフェクトをかけても勝手に回転しないし、回転処理を行なっても正しい結果が返ってくる様になった。

描画処理のどこかがまずいのかと散々頭を悩ませた結果、大本の画像に不備があったというオチでこの問題はかなりまいった

大きい画像を回転させようとするとUIGraphicsGetImageFromCurrentImageContextで落ちる

画像を回転させる場合、例えばこんな感じでやっていたのだが、大きな画像をこれで動かした時はUIGraphicsGetImageFromCurrentImageContextで落ちる事がわかった

    UIImage *img = self.image;
    CGImageRef imgRef = [img CGImage];
    CGContextRef context = nil;
    
    UIGraphicsBeginImageContext(CGSizeMake(img.size.height, img.size.width));
    context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, img.size.height, img.size.width);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextRotateCTM(context, M_PI/2.0);
    
    CGContextDrawImage(context, CGRectMake(0, 0, img.size.width, img.size.height), imgRef);
    UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();

原因としてはメモリ不足っぽいので、暫定処理として解像度を少し落として回転をさせるようにした。とは言え解像度を落としたくないので出来れば別の手段が欲しいなあ

    UIImage *img = self.image;
    CGImageRef imgRef = [img CGImage];
    CGContextRef context = nil;
    
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(img.size.height, img.size.width), NO,  [[UIScreen mainScreen] scale] * 0.7);
    context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, img.size.height, img.size.width);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextRotateCTM(context, M_PI/2.0);
    
    CGContextDrawImage(context, CGRectMake(0, 0, img.size.width, img.size.height), imgRef);
    UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();

追記:

これでもiPhoneのカメラで取った画像なんかを回転させると正常に回転出来なかった。2448*3264の写真を回転させると絵はそのままに3264*2448になるので単純に横にのびただけの画像になってしまうので駄目だ

 

さらに追記:

追記に書いた問題は別問題だった。解決済み

UILabelのframeとtextから適切なfont sizeを取得する

textとfontからUILabelのframeを適切なsizeにするのはいくつもあったけど、タイトルの様な処理は見かけなかったのであんまり需要はなさそうだけど書いてみた。

今作ってるアプリケーションで任意のfont sizeを指定されたUILabelがUIVewにaddsubviewされる場面があるが、過剰なfont sizeでも画面に収めたい。

その際画面に対しての縮小率がわかっているUILabelのframeとそのtextをベースにして縮小されたflameにピッタリ収まるようなfontを取得したいという所で下記みたいな処理をするようにした

- (UIFont*)getFrameFitFont:(CGRect)frameSize text:(NSString *)text{
    BOOL checkFitFont = YES;
    UIFont *font = [UIFont systemFontOfSize:1];
    
    while (checkFitFont) {
        CGSize textSize = [text sizeWithFont:font];
        
        if(textSize.width < frameSize.size.width){
            font = [UIFont systemFontOfSize:font.pointSize + 1];
        }else{
            font = [UIFont systemFontOfSize:font.pointSize - 1];
            checkFitFont = NO;
        }
    }
    return font;
}

知らないだけでもっとスマートに取得できる方法があるような気もする

UIImagePickerControllerを回転対応させる

以前書いたこれについての問題は解決した。

前回のエントリを見てもらえるとわかると思うが、UIImagePickerControllerはUINavigationControllerを継承しているので回転系処理に一工夫する必要があった。

UIImagePickerControllerを継承したCustomUIImagePickerControllerを作成し

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

を加えて終わり。UIImagePickerControllerの代わりにこのCustomUIImagePickerControllerを使えば回転してくれる

 

UINavigationControllerでUpsideDown時にイベントを取得する

UINavigationControllerで表示しているviewを回転させても何故かUpsideDownの時だけwillAnimateRotationToInterfaceOrientationが呼ばれない。

どうやらUINavigationControllerだとUpsideDownは抑制されているのでUINavigationControllerを継承したclassを作成しないといけないらしい。

ここを参考に実装した所、正常にイベントが取得できた

横向き状態でUIImagePickerControllerを使いフォトライブラリを触った時

シミュレータ上だけど強制的に縦向きに切り替わる

フォトライブラリから写真を選択した後は横向きに戻るので不自然な動作に見えてしまう。

横向きしか許容していない状態でこの動作を行うと強制終了するし、ALAssetsLibraryを使った場合も縦向きになってしまうので、自然な動作は横向きのままフォトライブラリにアクセスする事だと思うけど、フォトライブラリを表示する際は縦向きが基本なのかもしれない

どっかのガイドラインに書いてあるのだろうか

 

解決したので追記:

UIImagePickerControllerを回転対応させる