[iOS7] UITableView の境界線を separatorInset= UIEdgeInsetsZero で変えた時の副作用

2013年12月9日月曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

iOS7になってから UITableView の区切り線の左が短く切れた表示がデフォルトとなった。

iOS6までのように左まで線を引くにはいくつか方法があって一番簡単なのは appearanceを使う方法。ネットでたくさん出てた。
[UITableViewCell appearance].separatorInset = UIEdgeInsetsZero;
するとこうなる。アプリで使うすべての UITableViewが対象になるのでこれは便利。


ところがこれを使った場合メール送信のモーダルビュー表示で問題が出た。ツールバー上のボタン押下で MFMailComposeViewControllerを表示していたところ、iOS7だとメール編集画面が一瞬表示されてしまった後にすぐに閉じてしまうという現象が出た。

↑一瞬出てすぐ消える。
コンソールには次のエラーが出てた。
_serviceViewControllerReady:error: Error Domain=NSCocoaErrorDomain Code=4097
 "The operation couldn’t be completed. (Cocoa error 4097.)"
なんかおかしい。同じプログラムでも iOS6で動かすとこの現象は出ない。

調べてみると UIBarButtonItem などのアピアランスをカスタマイズしているとこの現象が出るらしい。

Cannot show modal ViewController in iOS7

MFMailComposer Dismissing immediately after launch


ただ自分のところでは UIBarButtonItem.appearance は設定していない。ネットで色々調べたが最初は原因がわからなかった。 コードを見なおしていると appearanceを設定している箇所 [UITableViewCell appearance].separatorInset にふと気が付き、試しにこれをコメントアウトしたところ正常動作するようになった。これが原因だったか。

これでモーダルビューの表示は解決したが、このままだと境界線が切れたままになるので境界線の設定を別の方法を使う必要がある。調べたら下記サイトが参考になった。

AmebaアプリのiOS7対応時に行ったUI実装

appearanceで一律変更設定をするのではなく Interface Builder でテーブル一つ一つの Separator Insets を設定してやる。
タイプを Defaults → Custom に変更しLeft=15を Left=0にしてやる。
テーブルがたくさんある時はコードで対処するのが良さそう。自分の場合は全部手で設定した。




最速カレンダー登録アプリ KickCal をリリースしました

2013年11月12日火曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

お手軽にデータ登録できる Kickシリーズ(?)の第2弾 KickCal をリリースしました。iOS7専用です。





取り立てて新しいものではありませんが個人的に欲しかったので作りました。単一機能に絞り、シンプルで使い勝手の良いアプリを目指しました。小さなアプリなので開発面では Autolayout や Storyboardを実戦で使う良い機会になりました。


半透明効果には下記のライブラリを使っています。iOS7っぽいところを出したいと思い、多少デザインの統一感が崩れますが入れてみました。


Kickシリーズはもう一本作ろうと思ってます。
無料なので良ければお試し下さい。



アプリのできるまで KickReminder

2013年9月16日月曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

着手から申請まで2週間程度でさくっと作ったアプリが先日リリースされた。
※8/26-9/8ぐらい




最近リマインダをよく活用するようになったが、標準アプリではアラームの設定が少々面倒でいつもストレスがかかる。そこでもっと速く登録できることに特化したものを作ってしまえと勢いだけで開発してみた。なお類似のアプリはすでにいくつかあったが自分の用途にはしっくりこなかった(あったら作ってない)。

今回はユーザインターフェイスの変遷を中心に開発状況を紹介してみる。

8/26 最初のプロトタイプ
基本的に画面遷移はあまり好きではないので、
入力を1画面でやってしまうというアイディアは最初からあった。
最低限、リスト(グループ)と日時を載せる必要があるので
まずは効率面から日時を横スクロールにしてみた。
なお同様の理由でキーボードは出しっぱなしとした。
いちいち出たり・引っ込んだりするとうっとおしい。

が、実機に入れて使ってみるとこれは非常に使いづらい。
特に画面の上方で横スクロールさせるのはストレスがある。



8/27 選択を縦に並べた
リストと日時の選択を縦に並べた。見た目はともかく
操作感は悪くない。基本型がここで固まった。
それとデザイン入れ。
プログラミング中にデザインを入れるのは開発スピードを殺す
最大の原因なんだけど、ついついやりこんでしまう。
デザインが入っている方が俄然やる気出るしね。
(※アプリは全部1人で作ってるのでデザインも自前)

フラットは基本にするとしても、白だけだとあまりにもしょぼい
感じがしたので枠を意識したカラーリングを入れてみる。
日付・時刻の並びは日→時の方が自然なので入れ替えた。
あとこの時点ではアラームを切る機能はテーブルビューの
セルに入っていた。


8/28 デザイン中
最上部にナビバーがあるのが標準的だがiPhone5の片手持ちでは
指が届きづらい。そこで下に持ってきた。標準と外れるが
利便性はいい。リストや日時のセル高さも低くなってきた。
この部分は何度も見た目と押しやすさを実機で確認しながら微調整した。
(おじさんの指の大きさだけでの確認だけど)


8/29 デザイン・デザイン
デザインは試行錯誤の連続。機能実装をそっちのけで
ああでもない・こうでもないとデザインを重ね、
実機に入れて何度も何度も眺め・さわりまくる。
こんなことやってたらいつまでたっても完成せんわな。
でもこういう時が一番楽しかったりする。
使い勝手はともかくナビバーは一番上にあるのが
デザイン的にはしっくりくる。


8/29 リストとアラーム用のツールバー
アラームの取り消しボタンは日付列の一番上においていたが
これはわかりにくいし使いづらい(いちいち一番上にスクロールが必要)。
どこかに置きたいがどうしても良い置き場がみつからない。
保存ボタンのバーでは意味合いが違う配置になるし、
遠すぎるので関連が薄くなる。
1行分取られるがツールバーを導入することに決めた。

あとこの辺りから履歴と追加情報(メモや優先順位)の
開発にも着手。時計のアイコンや三本線を作り
テキストフィールドの左右に配置。これを押すと左右に
画面がスライドして半開き状態でそれぞれの機能が
使えるようになる。左右スワイプでも左右画面を開けるが
明示的に機能の存在を示すためにアイコンは配置してある。


8/29 微調整
ひたすら変更→実機確認を繰り返す。


8/30 微調整
保存ボタンは文字だけにした。わかりやすいように
左に✓アイコンをつけてみた。このアイコンは
保存可能な時だけ緑色になり、そうでない時は
灰色となる(ボタンも押せない)。
アラーム用のツールバーは試行錯誤中。



9/3 ほぼ完成
アラーム用のツールバーは文字説明を記載。
文字は場所を取るので最初はアイコンも検討したが最後は文字にした。
冗長だがひと目でわかる、というのが一番の理由。


9/8 完成
できたー。必要な準備を整え申請。

追加情報画面。これまで紹介していなかった。

こちらは履歴画面。右スワイプで開く。

- - - -
今回のコンセプト=「シンプル」+「速い」
最初にコンセプトと決めていたので仕様面のブレや技術的な課題は無かった。なので作業の大半はユーザインターフェイスのデザインが中心になった。これだけ短い期間で開発したのは初めてで、開発速度が非常に遅い自分的には「あ、やればできるじゃん」的な妙な自身がついた。

アイコンやアプリ名は開発の一番最初につくるべきじゃないかと最近思い始めた。アイコンはラフスケッチでもいい。今まではアイコン作りや名前を考えるのは開発の後期も後期に着手していつも「ウンウン」困っていた。でもアプリのコンセプトって最初に決めるわけだから、本当はそれに合わせた名前とアイコンは最初に用意すべきじゃないかと(普通はそうだよね。。)。その方がコンセプトがブレにくいし、アイコンやアプリ名を眺めることで迷った時でも筋を通すことができる、気がする。もちろん最初のデザインは絶対では無いのでその後変わっていっていいと思うが、最初に決めることで方向性が明確になると思った。あと技術者が一人でアプリを作るとどうしてもプログラミングファーストになるけれど、作ったものをユーザへ提供する視点=マーケティング的な視点に立つなら最初のアプリ名やアイコンを含めた最初のコンセプトは重要だな、と今回はしみじみと感じた次第です。おわり。


リマインダを活用する方におすすめ。


写真鑑賞アプリ【 Viewing Fun ! 】

2013年7月20日土曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

新しいアプリをリリースしました。Viewing Fun !という写真ビューアです。自分自身が欲しいと思っていた写真ビューアを形にしたアプリです。

ランディングページ Viewing Fun !


今日の投稿はそのプロモーション記事です。


特徴

カメラロールの写真を見るためのアプリ。写真は1日単位で1ページにまとめられていて、3つのビューで写真を眺めることができる。
※スクリーンショットは古く最新版と若干異なります。


「アルバム」ビュー


1日の写真を大小様々な大きさの枠に自動配置して表示するビュー。写真をタップすると全体表示ができる(すべてのビューで共通)。


左右にフリックすると前日・翌日と移動ができる(これは3つのビューで共通)。


「マップ」ビュー


1日の写真とその撮影場所の地図を同時に表示するビュー。


番号で写真と地図が対応づけられている。写真はフリックで上下にスクロールできてそれに合わせて地図もスクロールする。写真と地図を眺めながら時間軸に沿って撮影場所を追っていくことができるようになっている。


「タイムライン」ビュー


1日の写真を時系列に並べたビュー。


デフォルトで1時間単位に折りたたまれていてタップすると開閉する。時系列に写真を見ながら撮影時の状況を追体験できる。


カレンダービュー


月単位で写真が眺められるビュー。


左右にフリックすると前月、翌月と移動できる。日付の色は写真の枚数によって青(薄い)〜赤(濃い)と変化する。


スライドショー


ズームとスクロールによる動きのあるスライドショーをランダムに表示する。約4秒間隔で写真が切り替わっていく。


カジュアルにスライドショーが楽しめるようトップレベルに開始ボタンを設置していて、設定無しですぐに始まるようにできている。


コンセプト


私は週末など出掛けた時にiPhoneを使って数十枚の写真を撮影しますが、多い時には100枚以上にもなることもあります。これを後からiPhoneで手軽に見返したいというのがこのアプリ開発のきっかけでした。作る前にはいろいろなアルバムアプリを購入して試してみましたが自分が欲しいものが見つからなかったというのも動機の一つでした。どれもしっくりこないのです。その大きな理由の一つとして、ほとんどのアプリは「整理する」ことがメインで、「見る」ことはどちらかというとオマケ的だと思えたからです。もちろん「見る」機能自体はどのアプリもしっかり作りこまれているのですが、ほとんどのアプリで写真閲覧のユーザインターフェイスが標準のアプリとほとんど同じでした。私の場合、写真整理はしないので、写真を見るなら標準アプリでも十分でわざわざアルバムアプリを使う理由がありません。それとこのユーザインターフェイスが出てから数年経つのに工夫が感じられない点も不満を感じていました。そんななか次の自作アプリのネタを探していたこともあり、無いなら作ってしまえとばかりに開発を始めることにしました。開発するにあたっては「見る」ことをメインとして「整理」は二の次、いや無くても良いぐらいの考えでイメージを考えてプロトタイプを作り始めました。今までのアルバム・ビューアに感じていた「見る」点の不満を解消して新しいアルバムアプリ(ビューア)を形にすることを目標にしました。

アプリ開発でこだわったのは次の点です。
  • 整理しないアルバム
  • 見ることが一番
  • 非サムネイル
  • 追体験
  • 1日でまとめる


整理しないアルバム


矛盾するフレーズですが「手動で整理しない」というくらいの意味です。人間が手で整理しなくてもコンピュータが自動的に整理してくれて手軽に写真が楽しめるのが今後の写真アルバムのあるべき姿だと個人的には思っています。iOS7の新しい写真アプリを見ると自動整理の兆候がちょっぴり見られますよね。現在人間が手動で整理せざるを得ないのは、人の好みに合わせて自動的に整理できるような高度な写真アルバム(アプリ)が無いからで、いずれ整理のメインは自動になると予想しています。理由は単純で、スマホの出現によって手軽に写真が取れるようになった一方、撮り貯めた写真が膨大になってきていて人間の手では整理しきれなくなりつつあるからです。

と、大げさに書いたもののこのアプリ自体は自動整理といっても1日単位にまとめるぐらいしかやっていません(自動と呼べるかも疑問ですが)。そして整理機能を持たない一番の理由は、私自身がものぐさで写真の整理ができない、だから使わないというのが理由です。また世の中の多くの人が恐らくそうだろうとも仮説を立ててみました(ものぐさなのは私だけじゃないですよね...?)。なので「整理せずに写真を手軽に楽しめる」ということがアプリの中心コンセプトとなりました。その為にはどういうビューや機能を用意すべきか、と。


見ることが一番


アルバムアプリの機能は大きく「見る」(鑑賞する)ことと「整理する」ことの2つだと思います。ただ多くのアルバムアプリは後者に力点が置かれていて、前者の「見る」機能が正直なところなおざりにされていると感じました。もちろん「見る」機能はちゃんとあるのですがiPhone標準の写真アプリとほとんど変わらないサムネイルと全体表示のスライドショーの構成、アプリによってはカレンダーと地図表示があるぐらいでした。アルバムアプリを見るにつけて常にこの点が不満でした。せっかく「整理する」機能はどれも工夫されているのに、一番利用することが多いだろう「見る」ことがあまり深く考えられていません。アルバムアプリは「整理」が主目的と言われればそれまでなのですが。。
だからこのアプリでは前述の「整理しない」ことと合わせて「見る」ことを最優先に考えました。複数のビューに加え、動きのあるスライドショーを入れたは、まさに「見る」ためです。またスライドショーに関しては、他のアプリと違いこのアプリで開始ボタンがトップ画面で目立つところにあります。このボタンをワンタップするだけで面倒な設定もなしでいきなりショーが開始されます。これはスライドショー自体をスキマ時間に楽しんでもらえるようなカジュアルなものにしたかったからです。またズームや移動を盛り込み、順番もランダムにして飽きさせないような工夫もしてあります。

なおスタンプを貼ったり、デコレーションしたり、様々なレイアウトフレームに配置したり、といったアプリはたくさん出ています。この点、「見る」ことに関して実際はいろいろと工夫されていると思います。ただし、それらの機能を持つ多くのアプリはコミュニケーションのツールとしての利用(友達に渡す、仲間と共有するなど)が前提で、写真自体を鑑賞する目的のアプリはあまりありません(いやあることにはあったのですが自分の用途にはイマイチでした。。


非サムネイル


サムネイルを否定しているわけではなくiOS標準の写真アプリを起源に持つステレオタイプ的なUIを指してしています。世に出回っているアルバムアプリは、最初にサムネイル表示されていてタップすると全画面モードを表示するものがほとんどです。これに加えて地図やカレンダーが付いているものもありますがそれらの画面でもサムネイルが基本です。このサムネイルはたくさんの写真を並べるには効率的ですが、普通に眺めるのには小さすぎます(老眼になりつつあるおじさんの眼では正直つらい..)。とても写真を楽しむ大きさでは無いと思ってました。かといって全画面モードではたくさんの写真を効率的に見ることができません。現在の多くのアルバムアプリはこの中間が抜けているのです。多くのアルバムがこのスタイルを取っているのはiPhoneの画面が小さいということもありますが、一番の理由は標準の写真アプリがこのスタイルだからでしょう。そこになんの工夫が無い点も開発者の立場から言えば不満でした。

そこで一番最初にプロトタイプを作った時にはまずサムネイルではなく、画面の1/2〜1/3程度の大きさで写真を並べるところから始めました。その結果、いくつもの写真を眺めるにはサムネイルよりも視認性が良く手軽に写真を楽しむのにはある程度の大きさがある方が良いことが実感できました。最初のプロトタイプを作ることで方向性が見えてきたので、それから自分が納得のいくビューができるまでは、作っては捨て・作っては捨ての繰り返しでした。ビューを試作したらすぐに手持ちのiPhoneへ入れて、移動中の時間などにそのプロトタイプ・ビューを自分で何度も何度もいじって使い倒しました。最終的には今の3つのビューになったわけですが、そこへ至るまでは結局プロトタイプで1ヶ月以上、最後のビューへ落ち着くまでは3ヶ月はかかりました。最後の最後の段階で切り捨てたビューもあります。実はサムネイル画面も用意しましたがこれも途中で捨てました。作ってみたもののやはりしっくりこなかったからです。なおカレンダー画面にはサムネイルが残っていますが、これはむしろサムネイルがぴったりの用途だからです。カレンダーは1ヶ月という単位で時間を俯瞰するので、そこで表示される写真も俯瞰的に見えた方が統一感が得られるからだと思いました(ちっちゃいけど)。


追体験


写真をとったあの時を今の自分が追体験すること、別の言い方をすると「撮影時のストーリーを思い出せる」こと、それが写真ビューアに求められることだと考えました。一番原始的なところでは写真を撮った日時とその時の場所が見られるということです。もちろん日時と場所の情報はほとんどのアルバムアプリでも見られます。しかし日時と場所を写真の単なる付加情報としてしか捉えていなくて、どちらかといえばオマケのように感じられました。そうではなく、写真を見る人が日時と場所を知りたいのは、その写真をとった時の状況を思い出すきっかけになるからです。私は、日時と場所の情報はその時を思い出す為の重要な情報だと考えています。それは「撮影時のストーリー」を思い出すきっかけであり、その写真をとった時のことを今の自分自身が追体験することへ導くからです。だから場所の情報は緯度・軽度ではなく地名で表示するのが自然でした。地図表示ももちろん役立ちます。幸いiOSのAPIには緯度・経度を元に地名を取得するものがあったので今回はこれを利用しています。今回はできませんでしたができればその時の天気やその土地の情報なども盛り込みたいとも思ってます。

このアプリでは、写真ごとの日時と場所の表示を基本とした上で「タイムライン」と「マップ」と呼ぶそれぞれ時間と場所を軸とする2つを用意しました。「タイムライン」は1日の写真を時系列に1時間単位に並べたものです。これは実際に見てもらうとわかるのですが写真と地名が時間に沿って表示されるのでその1日の行動を写真付きで後から時系列に眺めることができます。時系列にならんだ写真と地名を俯瞰できるので1日の行動の流れを思い出すのに役立つと思います。もう一つの「マップ」は上部に地図、下部に写真という構成になっています。特徴的なのは地図上のピンに番号がついていてそれが時間順になっていることです。つまり行動の足あとを後から追えるようになっています。写真にもこの番号がついていて、この写真がどの場所で取られたのかを地図上で容易に確認できます。この写真を上下にフリックするとそれに合わせて地図上の表示も変化していくので、写真をめくることで行動の軌跡をやはり自分で追体験することができます。


1日でまとめる


この考えは開発初期にはすでに固まってました。人が過去を思い出す時の時間の単位は1日が自然だと思ったからです(あの日にどこどこへ行ったんだっけ、みたいな)。開発初期にはよくあるように1枚の画面に全ての写真をならべ、セクション(見出し)に日付を付けるようなUIを試していました。しかしこのUIは大量の写真を扱うにはサムネイルにせざるを得ない為あきらめました。また1画面に複数の日の写真が同時に目に入ってくる為に「追体験」という意味では写真が楽しめない(集中できない?)と感じました。思い出の単位が1日なら、見せ方もそれに合わせた方が自然ではないかと。それらの理由から1画面で表示するのは1日分の写真だけ、という今の基本UIに決めました。ただこの時どうやって他の日へ移動するかが課題になります。これには左右へのフリックを割り当てました。一方、上下のフリックは1日の中の時間軸の移動に統一してあります。この2つのルールは3つのビューで共通です。なおスライドショーのみはこのルールから外して左右フリックとしました。開発中に上下フリックを試してみたのですがかなり違和感があったからです。こうして1日単位のUIが定まると今度は任意の日へ移動する手段が必要なります。その為にカレンダーのビューを作りました。この点、多くのアルバムアプリが取っているカレンダービューを基本としているのとは真逆のアプローチとなりました。


-----

とまあ色々書きましたが、気軽に楽しめるアプリです。
無料なので良かったらどうぞ試してみて下さい。

Viewing Fun !




10分でおぼえるBlocksの書き方

2013年7月18日木曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

Blocksが使えるようになってはや数年。未だに書式が覚えられないわたし(あなた)の為に書き方をまとめてみた。

基本


基本型


 戻り値 (^名前) (引数)
(私が勝手に決めた)基本型はこれ。これを覚えないことには始まらない。とにかくこれだけは覚える。
戻り値と引数は一般的なCの関数の書き方と同じなので、名前の書き方だけ (^名前) になったと覚えるのがいい。
(例)BOOL (^completion)(BOOL canceled) = ...;
この基本型を元に各場面でどう使うかを見ていく。

変数宣言・typedef宣言


変数宣言なら
 戻り値 (^名前) (引数) = …;
typedef宣言なら
 typedef 戻り値 (^名前) (引数);
両方とも基本型がそのまま使える。

(例)typedef BOOL (^LKCompletion)(BOOL canceled);

プロパティ宣言


プロパティ宣言で使う時にも基本型がそのまま使える。
 @property (copy) 戻り値 (^名前) (引数)
Blocksをプロパティ宣言する場合は copy にしておくのがポイント。
(例)@property (copy) BOOL (^completion)(BOOL canceled);

メソッド引数


メソッド引数にした時に書き方が若干変わる。形が変わるのが Blocks構文を覚えにくくさせている理由の一つ。
(例)- (void)loadImageCompletion:(BOOL(^)(BOOL canceled))completion;
ただ落ち着いて見るとObjective-C標準のメソッド引数の書式に従って基本型を変形しているだけなので実は難しくない。

もともとメソッド引数は「(型)名前」というスタイルなので基本型をそれに合わせて変形ればいい。
戻り値 (^名前) (引数)  ※基本型
 ↓
 ↓ 名前を後ろへ切り出す ←メソッド引数名は最後にくるから
 ↓
戻り値 (^) (引数)名前
 ↓
 ↓ 引数の型となる範囲を( )で囲う ←メソッド標準の書き方
 ↓
(戻り値 (^) (引数)) 名前
基本型をメソッド引数の書き方に合わせたものだと覚えておくといい。


Blocks定義


 ^戻り値 (引数) {...}
やはりBlocks構文を覚えくくさせている原因の一つ。基本型と書き方が異なる。
(例)BOOL (^display)(BOOL animated) = ^BOOL(BOOL animated) {return YES;};
こちらはメソッド引数の時と異なり変形ルールが想定できない。仕方がないので基本型同様に暗記する。なおメソッド引数にBlocks定義を記述する場合、Xcodeならコーディング時にBlocksの書式を補完してくれる。この為記憶を頼りに記述するケースは実際には多くないかもしれない。

(例)[hoge loadImageCompletion:^BOOL(BOOL canceled) {
    :
   }];


まとめ


こうして見ていくとBlocksの書き方が覚えにくいのには理由があって、書き方のパターンが何種類もあるのが原因だとわかる。逆にそれらが整理できて把握できれば自分で書けるようになる。

最低限覚えるべきは次の2つ。

基本型

 戻り値 (^名前) (引数)

Blocks定義

 ^戻り値(引数) {...}
それ以外は基本型がそのまま使えるのと、メソッド引数の場合は基本型の応用なので変形ルールを知っておけば書式を無理に覚える必要は無い。またBlocks定義を書く時は、多くの場合 Xcodeが補完してくれるので覚えておく必要性は基本型に比べると実は少ない(人によるが)。なので、乱暴に言えば基本型だけ覚えればどうにかなる。

なお「基本型」など、この記事の分類は私が勝手に決めたものなのでご注意を(公式の呼び名ではない)。


応用


voidな引数と戻り値は省略できるケースがある。

引数省略


引数が voidの場合は省略できる。

BOOL (^execute)(void) = …;
 ↓
BOOL (^execute)( ) = …;
- (void)displayScreen:(void(^)(void))didAppear;
 ↓
- (void)displayScreen:(void (^)( ))didAppear;

戻り値省略


Blocks定義の時は戻り値が voidであれば省略できる。
(例)^void (void) { … }
    ↓
   ^(void) { … }
Blocks定義の場合、引数が voidならさらに引数のカッコ ()自体も省略できる。
(例)^{ … }
よく見かける ^{...} は実は ^void(void){...} が省略されたもの。

Blocks定義以外で戻り値voidは省略できないので注意。
○ @property (copy) void (^didAppear)(BOOL animated);
☓ @property (copy) (^didAppear)(BOOL animated);


参考・お役立ち情報


Block Cheat Sheet

Block Declaration Syntax List
Recursive Blocks(再帰ブロック)の書き方の紹介あり。

坂本氏担当の第5章にBlocksの説明あり。GCDと合わせてわかりやすい。


こちらも坂本氏の本。詳細な解説だがそれでいてわかりやすい。ARCの詳説もあるのでかなりおすすめ。私は紙で入手したが電子書籍版もあると思う。



- - - -
ツッコミあればお願いします。間違い等は訂正します。

ObjCがサクっと書けるコーディングTips

2013年4月21日日曜日 | Published in | 1 コメント

このエントリーをはてなブックマークに追加

最近よく使っている省略記法を紹介する。これらを使うとなんとなく気分がいい。

クラスメソッドの . (ドット)アクセス


実はクラスメソッドも .(ドット)表記が可能になった。
[SomeClass sharedInstance]
     ↓
SomeClass.sharedInstance
当然ながらさらにメソッドも重ねられる。

SomeClass.sharedInstance.localName
Xcodeではクラスメソッドの.表記は補完が効かないのが難点。ただしそれ以降のメソッドは補完してくれる。
例えば SomeClass.share... ここまでは補完しないが、SomeClass.sharedInstance.local.. ここまで来ると補完できる。


インスタンス作成 (1)new

お馴染みの alloc/init の代わりに new が使える。
SomeClass* obj = [[SomeClass] alloc] init];
     ↓
SomeClass* obj = [SomeClass new];
. を使えばさらに短くサクっと書ける
SomeClass* obj = SompeClass.new;
+new は NSObjectで定義されている(new = alloc+initとの説明がある)
This method is a combination of alloc and init.
NSObject Class Reference

昔からObj-Cにあったメソッドだが、ARCになってから autoreleaseが不要になったので使いやすくなった。

(参考)
objective c - What is difference between new and [[alloc]init] in iOS? - Stack Overflow


インスタンス作成 (2)self


クラスメソッド内でselfはクラス自身を指す。なのでインスタンスの作成に使える。
+ (instancetype)sharedInstance
{
 SomeClass* obj = [[self alloc] init];
  :
  :
}
さらに . と new を使えばこう書ける。
SomeClass* obj = self.new;

instancetype については下記を参照
Objective-Cにおけるinstancetype型について - Takebayashi.Asia


配列・ディクショナリ作成

githubでソースコードを読んでて知った。mutableな配列・ディクショナリもサクっと書ける。
NSDictionary* dict = @{}
NSMutableDictionary* dict = @{}.mutableCopy;
NSArray* array = @[]
NSMutableArray* array = @[].mutableCopy;


- - - -
多くはgithubで他の人のコードを読んでて知ったもの。コードを読むことはアルゴリズムを読み解くだけでなくコーディングのトレンドもわかるなー。

NSSecureCoding - セキュアなプロセス間通信への小さな布石

2013年4月20日土曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

NSSecureCoding という聞きなれないプロトコルが iOS6/OSX10.8から導入された。ここでいうCodingとはオブジェクトの永続化のプロコトル NSCodingのそれを指している。つまり NSSecureCoding はセキュアな NSCodingのこと。


NSSecureCodingの定義はクラスメソッドが1つあるだけ。
+ (BOOL)supportsSecureCoding;

使い方の前に何故この新しいプロコトルが導入されたかというと、現状のNSCodingだと不正なオブジェクトのロードを防げないから。
例えば -initWithCoder: の標準的な実装はこうなる。
id obj = [decoder decodeObjectForKey:@"myKey"];
if (![obj isKindOfClass:[MyClass class]]) {...fail...}
2行目でクラスチェックを行っているが実際には1行目でインスタンス化されていて既にその時点でクラスおよびインスタンスのイニシャライザは起動している。つまり現状では仮に不正なクラスが読み込み対象のファイルに紛れ込んでもその初動を防ぐことができない。

そこでNSCoderクラスに新しく -[NScoder decodeObjectOfClass:forKey:] が導入された。
NSCoder Class Reference

先程の2行の代わりに1行でチェックとデコードを同時に行う。
id obj = [decoder decodeObjectOfClass:[MyClass class]
            forKey:@"myKey"];
もし
(a)指定クラスがNSSecureCodingを実装している
(b)指定クラスとロードするクラスが一致する
のどちらかを満たさない場合は例外がスローされ、インスタンスの作成は行われない。これにより不正な振る舞いを防ぐことができる。なおこのチェックを有効にするには -[NScoder requiresSecureCoding]でYESを返すようにしておく必要がある(NOだとチェックは働かず実質 decodeObjectforKey:と変らない)。

この外部からのインスタンスロードのチェックに NSSecureCodingが使われる。このNSSecureCodingを実装するには次のどちらか2つの条件を満たす必要がある。
[a] initWithCoder: をオーバーライドしない
[b] initWithCoder: をオーバーライドする場合、decodeObjectOfClass:forKey: を使う
さらに + supportsSecureCodingをオーバーライドして、YESを返す必要がある。
この辺り、NScoderの条件と合わせると若干複雑な感じはする。

NSSecureCodingが導入されたのはXPC導入に伴うもので、iOSに関して言えばiOS6からXPCが導入された。このXPC導入に伴い、従来はアプリ内(1プロセス内)で完結していた動作がプロセス間での協調動作できるようになった。この為、従来の信頼できる自アプリ内の永続化データだけでなく、外部プロセスとの通信時に送られてくるデータの復元(decode)が必要になってきた。この時、攻撃者が何らかの方法で不正なクラス・インスタンスのデータを紛れ込ますことに成功した場合、従来の initWithCoder: ではチェックする手段が無い(※こういう攻撃方法を object substitution attacks と呼ぶらしい)。この対策としてNSSecureCodingを始めとする一連のAPIが導入された。

なお XPC Serviceを作ったり、直接アクセスできるのは今のところApple提供のライブラリだけ。一般開発者には公開されていない。このあたり次期iOS7でどうなるのかが非常に興味深い。


- - - -
今のところ一般開発者が使う理由があまり思いつかないが、XPCが公開された時には必須スタイルになるのかもしれない。



(参考)iOS6でのXPC利用


(参考)NSSecureCodingについて


(参考)XPCの概要




あけましておめでとうございます 2013

2013年1月1日火曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

2013年もよろしくお願いいたします。
毎年元旦には昨年の反省や今年の目標を書いているので今年も書き留めておきます。

----------------------------------------------------------------
昨年は、初の個人制作アプリの発売と事業の立ち上げなど個人的には大きなイベントがありました。時間を掛けて今までコツコツと進めてきた活動が実を結び、個人的に目標としていた1つのマイルストーンがようやく達成できました。

次のマイルストーンを目指し今年は下記のことを目標として立ててみました。

・情報局の日々更新
・このブログの更新(不定期)

そして
・Androidアプリ1本以上のリリース
・新作iOSアプリ2本以上のリリース

さらに
・iOSアプリと連携した OS X アプリのリリース
・Windows8アプリ1本(JSベースで)のリリース

とここまで書いて遠い目に..

まあ自分勝手に目標を挙げるのは自由なので書くだけ書いておきます。下になるほど指数関数的に実現性が低くなりますが。。

経験的には立てた目標を実現するのに2〜3倍ぐらいは期間はかかるかな(すると2〜3年?!)。もちろん中止するものもあります。ただ自分の開発スピードが非常に遅いことは自覚しているので、時間がかかってもマイルストーンに向けて一歩一歩近づけていければ良いかと。諦めなければいつか到達できると思います(たぶん)。

----------------------------------------------------------------
iOS以外に手を出すのは、収入源が Apple1社依存ではリスクが高いといまさらながら思ったからです。昨年のApple都合による支払い遅延(2ヶ月も!)でそのリスクを実感しました。Appleの場合、今後もルール変更により同様に収益に影響を受ける可能性は十分にあると思います。趣味で作っているうちは良かったのですが、アプリ制作を事業の柱として考えた時に収入を1社に依存することはリスクがあると痛感しました。今年は売上を増やすと同時に収入源を分散させることを事業の目標として行きたいと思っています。またプラットフォームを変える他、広告やアプリ内課金の取り組みもやってみたいと考えています。

また昨年後半はアプリ制作に専念したせいでブログの更新が滞り、その結果新しいことを勉強する機会が減ったと感じました。情報の消費スタイルは従来と変らなかったのですが、アウトプット=発信が無いことで情報の理解力・吸収力が低くくなったと実感しました。やはり知ったことは人に話したり、書いて発信していかないと身にはならないですね。
アプリリリース後はそのバージョンアップとメンテナンスが中心になったことも、新しい事を手がけない傾向に拍車を掛けたと思います。それを反省し昨年末からリハビリを兼ねて情報局を再開しました。このブログも不定期ながらも何らかの記事を挙げて行きたいと思っています。AndroidやWindows8を手がける理由も新しい刺激を求めてということもあります。

そんなこんなで色々あると思いますが
今年もまたよろしくおねがいいたします。

人気の投稿(過去 30日間)