iOS7以降でUITableViewCellをカスタマイズするときに気をつけること
iOS7以降のUITableViewCell
UITableViewのセル単体を管理するためにUITableViewCellを使います。iOS7以降になると標準のUITableViewCellの左端に微妙な隙間ができました。UITableViewCellをカスタマイズせずにそのまま使う場合は問題ありませんが、カスタマイズする場合はこの点に気をつける必要があります。
UIImageがベタ塗りされたときの対処法
UIImageがベタ塗りされる
ちゃんと画像を指定しているのに、真っ白になったり真っ黒になったり画像が1色でベタ塗りされたことがありました。そういえば、iOS7対応したときにいろんな画像が青色にベタ塗りされた記憶が…。ということで調べてみた結果が下記です。
AutoLayoutとうまく付き合うコツ
AutoLayoutと仲良くなった
ぜんぜん言うこと聞かないからAutoLayout大嫌いだったんですが、接し方を変えたら言うこと聞くようになったので、そのコツを紹介します。
Images.xcassetsでアプリのアイコンから光沢を消す
Images.xcassets
Xcode5から画像を一元管理できる仕組みとしてImages.xcassetsが登場しました。9Sliceも簡単に設定できたり便利です。
アイコンに光沢が…
Images.xcassetsに画像を全部移行した後、アプリをインストールするとなぜかアプリのアイコンに光沢がかかってしまいました。
設定が間違っていたようで、「iOS icon is pre-rendered」にチェックをいれると光沢がなくなりました。
UIWebViewで特定のURLの末尾にパラメータをつける
UIWebViewでページを読み込む前のイベントをキャッチ
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { //WebView内のロードする前に呼ばれる }
UIWebViewDelegateの「webView:shouldStartLoadWithRequest:navigationType:」メソッドを使えば、WebViewでページを読み込む前のイベントをキャッチできます。つまり、WebView内でリンクをクリックしてそのページが読み込まれる前に呼ばれます。navigationTypeでクリックしたかどうかなどを判定できます。
http, https以外のリンクは特定のアプリにとばす
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *urlScheme = request.URL.scheme; if (![urlScheme isEqualToString:@"http"] && ![urlScheme isEqualToString:@"https"] && [[UIApplication sharedApplication] canOpenURL:request.URL]) { [[UIApplication sharedApplication] openURL:request.URL]; return NO; } }
引数の「request」からURLを判断して、特定のアプリになげることも可能です。returnをNOにすることで、WebView内でのロードをストップさせてます。
特定のURLの末尾にパラメータを付加
- (BOOL)webView:(UIWebView *)_webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *url=request.URL.absoluteString; NSString *param = @"smartphone=1"; NSRange extraParam=[url rangeOfString:param]; NSRange hatena = [url rangeOfString:@"?"]; NSRange conditionURL =[url rangeOfString:@"hogehoge.com/hoge/"]; if(extraParam.location == NSNotFound && hatena.location == NSNotFound && conditionURL.location != NSNotFound){ url = [url stringByAppendingString:[NSString stringWithFormat:@"?%@", param]]; NSURLRequest *newRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]]; [_webView loadRequest:newRequest]; return NO; }else if (extraParam.location == NSNotFound && hatena.location != NSNotFound && conditionURL.location != NSNotFound){ url = [url stringByAppendingString:[NSString stringWithFormat:@"&%@", param]]; NSURLRequest *newRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]]; [_webView loadRequest:newRequest]; return NO; } return YES; }
次に表示するURLに特定の文字列が含まれている場合、それを付加するという処理になっています。パラメータがある場合とない場合で連結する文字が「&」「?」で変わるので分岐してます。
あとはloadRequest:メソッドで文字列を付加したページを読み込みにいけばOK。
パラメータを付加しない場合もあるので、その際はそのままWebView内の処理を続ければよいのでreturn YESを返しておきます。
Watch Kit AppとiPhone App間でNSUserDefaultsを使ってデータ共有をする
Watch Kit AppとiPhone Appのデータは別管理
基本的にWatch Kit AppとiPhone Appがそれぞれ保持するデータ領域は別々に管理されています。したがって、下記の設定を行わずにNSUserDefaultsを使ってみると、Watch Kit Appで保存したデータはWatch Kit Appからしか利用することはできません。逆もしかり。
Watch Kit AppとiPhone App間でデータ共有できたらいいなぁと考えますよね。
そんなときはApp Groupsを設定してあげればOK。
App Groupsを作る
Watch Kit App はiOSのExtentionと同じ仕組みで動作します。
iPhone Appとのデータ共有をする際は、App GroupsというIdentifierを使う必要があります。
作り方は簡単。iOS Dev Centerの「App Groups」から新規にIdentifierを設定します。
名前は「group.jp.co.hogehoge」みたいな感じで、接頭辞に「group」をつけることが推奨されています。
App GroupsをXcode上で設定する
XcodeのTARGETから「Capability」タブを選択し、App GroupsをONにします。
さきほど作ったIdentifierを設定すれば完了。
ちなみにこの作業はiPhone AppのTARGETとWatch KitのTARGET両方に設定する必要があります。片方にしか設定していないとデータ共有がうまく行われません。
NSUserDefaultsからデータの読み込みおよび保存
App Groupsを作ればあとは、いつものようにNSUserDefaultsを使えばデータを共有することが可能です。
データの保存
NSUserDefaults *storage = [[NSUserDefaults alloc] initWithSuiteName:@"group.jp.co.hogehoge"];
[storage setObject:data forKey:WATCH_APP_KEY];
[storage synchronize];
データの読み込み
NSUserDefaults *storage = [[NSUserDefaults alloc] initWithSuiteName:@"group.jp.co.hogehoge"];
NSData *data = [storage objectForKey:WATCH_APP_KEY];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSUserDefaultsでinitWithSuiteName:を使ってApp GroupsのIdentiferを使って情報取得する必要があります。
WatchKit AppからiPhone Appを起動する方法
Watch App側の実装
[WKInterfaceController openParentApplication:@{} reply:^(NSDictionary *replyInfo, NSError *error) {}];
WKInterfaceControllerのopenParentApplication:reply:メソッドを使うことでiPhone側の親アプリを起動することができます。現在のところ、親アプリのみ起動が可能です。
一つ目の引数に渡したいデータを入れればOK。
iPhone App側の実装
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply
Watch Kit App からiPhone側の親アプリが起動されたとき、application:handleWatchKitExtensionRequest:reply:メソッドが最初に呼ばれます。渡ってきたデータをごにょごにょできますね。
URLスキームを設定していれば、特定のページへ遷移させることも可能です。