2014年05月17日

[iOS] 今更聞けないRetinaディスプレイの話

エモトです.Microsoftが新しいSurfaceを発表すると言われる日が給料日近くで,とてもそわそわしています.Microsoftが出すハードウェアはやっぱり良いですよね.

最近のニュースで,iPhone6で解像度がさらに上がるかもしれないという話が出てましたね.Retinaディスプレイは2010年に登場しましたが,改めてRetinaディスプレイの話と,3倍Retina(仮)が来たときに開発現場で何が起こるのかを話しましょう.

Retinaってなに?


iPhone4からRetinaディスプレイが採用され,画面解像度が480x320ピクセルから960x640ピクセルの2倍になりました(iPhone5で画面サイズは縦長に変わりましたが,考え方は同じなので省略).これは画面サイズを大きくするためではなく,従来の1ピクセルを2x2ピクセルで表示することで,画面をより精彩に表示するのが目的です.

解像度が異なる端末間でアプリ内の座標系に互換性を持たせる(Retina端末でも非Retina端末でも同じ配置で表示させる)必要があるため,アップルはRetinaディスプレイ採用後に,座標系にポイントという新しい概念を導入しました.
非Retinaの座標系において,1ポイント = 1ピクセル
Retinaの座標系において,1ポイント = 2ピクセル
これにより、Retina端末でも非Retina端末でも座標系は480x320ポイント(iPhone5なら568x320ポイント)になり,解像度が異なっても同じ座標を維持することが出来ます.

Retinaでデザインするときの注意点は?

ポイント座標系でボタンなどの配置を考えます.しかしながら,画像に関しては,精彩に表示するため,本来のピクセル座標系でのサイズも必要になります.この2つの座標系を行き来して作成するのは億劫なので,ポイント座標系ではなくピクセル座標系でデザインをしたいと考えますが,落とし穴があるので,注意が必要です.

例えば,ピクセル座標系で(x,y) = (1,1)を指定すると,実際のアプリ内でのポイント座標系では(x,y) = (0.5,0.5)となります.座標は整数値でしか指定できないので,四捨五入するかして,指定通りには配置はできません.乱暴ですが,ピクセル座標系で指定する場合は,偶数でしか指定できないと思ってください(今のところは).

Retinaが三倍になったら何が起こる?

3倍Retina端末において,1ポイント=3ピクセルになりますが,アプリはこれまで通り,ポイント座標系で作成していきます.

起こりうる問題として,ポイント座標系を意識せずにデザインを行った場合です.ピクセル座標系でデザイン指定を6ピクセル(2と3の最小公倍数)単位で行えば,問題なくポイント座標系へ変換できますが,それ以外では整数値にはならないため,ポイント座標系への変換が上手く行われません.折角のデザインが不格好になるだけです.

それではどうしたら・・・

ポイント座標系でデザインしましょう.画像で複数の座標系を扱うので億劫になりますが,iOS7から採用されたフラットデザインをうまく活用して,なるべく画像を使わずに作成・表現するなどして,対応するといいでしょう.

ちなみに,私は3倍Retinaを見越してるわけではないですが,簡単な形状であれば,画像は使わずにアプリ内で生成して,アプリ内での画像使用を控えるように心がけています.できる・できないもありますので,デザイナーの方は,開発者と相談するといいでしょう.
posted by Seesaa京都スタッフ at 12:00| Comment(0) | iOS | このブログの読者になる | 更新情報をチェックする

2014年05月16日

[iOS] UIImageを比較したい

先日のGW,舞鶴鎮守府に着任しに行きました,エモトです.肉じゃが,美味しかった(*´ω`*)

二つの画像が同一かどうか比較したいが,そのデータの更新時間や元の画像ファイル名もなく,直接UIImageのインスタンス同士を比較するしかない場合のお話です.

Obj-Cには 比較メソッド「-(BOOL)isEqual:(id)object」が用意されているクラスがありますが,このUIImageクラスにはありません.そこで,このメソッドを自作します.方法としては,UIImageインスタンスを,比較メソッドを持つNSDataインスタンスに変換して比較を行います.冗長な比較をさけるため,最初に画像サイズを使って判定しています.
@interface UIImage (equal)
-(BOOL)isEqual:(UIImage*)image;
@end

@implementation UIImage (equal)

-(BOOL)isEqual:(UIImage*)image
{
    BOOL result = NO;
    if (image && CGSizeEqualToSize(self.size, image.size)) {

        CGDataProviderRef dataProvider1 = CGImageGetDataProvider(self.CGImage);
        NSData *data1 = (NSData*)CFBridgingRelease(CGDataProviderCopyData(dataProvider1));

        CGDataProviderRef dataProvider2 = CGImageGetDataProvider(image.CGImage);
        NSData *data2 = (NSData*)CFBridgingRelease(CGDataProviderCopyData(dataProvider2));

        result = [data1 isEqual:data2];
    }
    return result;
}

@end
NSDataへの変換は,DataProviderを用いてました.UIImageJPEGRepresentationを使えば一行で済みますが,計算時間を考慮して,前者にしました.なお,サイズ1920x1080の画像を用いた場合,DataProviderで0.089815 msec,UIImageJPEGRepresentationで0.206442 msecでした.

posted by Seesaa京都スタッフ at 12:00| Comment(0) | iOS | このブログの読者になる | 更新情報をチェックする

2014年03月10日

[iOS]MFMessageComposeViewControllerとMFMailComposeViewControllerが開かない

ベトナム滞在を延長しましたiOS担当の川口です。ハノイは、もうかれこれ2〜3週間雨で穴の空いた靴から雨が浸水する毎日を過ごしています。いい加減晴れて欲しいと願っています。まず靴を買えって話ですね...。

さて今回の本題ですが、MFMessageComposeViewControllerとMFMailComposeViewControllerについてです。
ある案件でMFMessageComposeViewControllerとMFMailComposeViewControllerを使ってメール送信機能を実装してiPhone5sでビルドしたところ、こんなエラーが出てメール画面が開きませんでした。

init Error Domain=NSCocoaErrorDomain Code=4097 "The operation couldn’t be completed. (Cocoa error 4097.)"
Remote compose controller timed out (NO)!

調べたら64bit端末で32bitビルドすると起こるバグみたいです。
Architecturesからarm64を外してたので、追加したら正常に動くようになりました。

posted by Seesaa京都スタッフ at 18:21| Comment(0) | iOS | このブログの読者になる | 更新情報をチェックする