2014年11月4日火曜日

【iOS8 対応】editActionsForRowAtIndexPathで標準メーラーのようなedit modeを実現するために

iPhoneの標準メーラーに搭載されているUIで
各cellをスワイプすると「削除」とかボタンがにゅるっと出てくるのありますよね?

あれがiOS8からuitableviewのdelegateメソッドとして使えるようになりました。

tableView:editActionsForRowAtIndexPath

基本的な使い方は、ブログで多く取り上げられていますが、

-(NSArray*)tableView:(UITableView*)tableView editActionsForRowAtIndexPath:(NSIndexPath*)indexPath {

UITableViewRowAction *deleteAction
= [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive
title:@"delete"
handler:^(UITableViewRowAction *action,NSIndexPath *indexPath) {

// ボタン押したときの処理

}

// ボタンの数はここで決まる
return @[deleteAction];

}

// これないとダメ
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexpath *)indexPath
{
 
}

以上が基本的な実装です。


が、これには欠点があります。
iOS7です。

現時点ではiOS7にも対応させなさいよ、っていうオーダーが多いと思います。

そこで対応方法をちょっぴりはまったので記載しておきます。


まず、iOS7でもこの状態でボタンが出てきます(なぜ?w)。

ただ、ボタンを押してもUITableViewRowActionのブロック内にきません。

どこいった?

ここで活きてくるのが、//これないとだめ って書いた
tableView:commitEditingStyle:forRowAtIndexPath
ここです。

これは本来、uitableviewのedit modeをYESにしたときに通るところなんですが、
今回の実装方法でボタンを押したときにも通ります。

ここはiOS8では通りません。


なので、ブロック内と同じアクションを書いておけばOKです。



さらに、特定のセルだけこのスワイプしてボタンが出るようにする場合は、
iOS7 8どちらも対応させるには、editActionsForRowAtIndexPathで
セルの判別しただけではダメで、

tableView:canEditRowAtIndexPath
でセル判別しないといけません。


tableView:editActionsForRowAtIndexPath
これがなんでiOS7で動くかなぞです。。。




2014年10月15日水曜日

ぞっとした一日(Transfer AppとKeyChain)

無事にアプリをリリースできたのですが、
初日に諸事情によりアプリを別のアカウントに移さないといけないことになりました。

調べてみたら、Transfer AppというiTunes Connectにそなわった機能で、
お手軽にアプリのアカウントを移せるとのこと。

いやーよかったよかった。。。





数日後、アプリのバグ改修等でアップデートのため、
最終チェックをTest Flight。

あれ?

チュートリアルから始まったぞ?

???


いろいろ調べた結果、ユーザーを特定するkeyが消えてます。


???


ここからさらに調べた結果、Transfer Appすると
Team IDが変わり、Team IDが変わると、アプリのAppIDPrefixが変わり、
KeyChainを使用しているともろもろ取れないぞ、と。

ほぉほぉ。

それならKeyChainのkeyに無理やり前回のAppIDPrefixぶちこめばいいじゃん。


・・・


それはセキュリティの問題でできませ~ん
とぅいまてーん。


絶望。。。


結果、3人がかりで1日試行錯誤し、ウルトラC級のアイデアにより危機回避できました。
ちなみに解決策は、たまたまユーザーユニークの値をUserDefaultに保存していたので、
そちらから逆算しKeyChainを新規AppIDPrefixで保存するという方法。

ちなみにちなみに、めっちゃ調べた結果、
Transfer App後のKeyChainの純粋な復帰は不可能です。
(Appleにも電話しましたw)

2014年10月2日木曜日

Facebook Paper

多分に影響を受け、感銘を受けました。
FacebookのUI研究チームが全力で作ったアプリだそうです。

http://blog.brianlovin.com/design-details-paper-by-facebook/

ここにPaper UIのなにがすごいかがまとめられています。


個人的に細かくチェックしてみましたが、
何点か気付かないものもありましたね。

「気付きにくいところに細やかな配慮」

これは元来「日本人」の特性であり美徳であると思います。


それはさておき、エンジニアっぽいことも記述。

https://github.com/facebook/pop

ここにPaperの一部アニメーションの技術があるのですが、
どうやらUIDynamicsを使用してるっぽいですね。




Paper的なの実装してーなー。。。





2014年9月16日火曜日

IFTTTのJazzHandsを使用したチュートリアルサンプル

使ってみました。

所感ですが、
できることできないことを把握して、これを使う前提でチュートリアルを組むなら
申し分ない出来です。
が、さらにリッチに動くものを作るとなると自前で
scrollviewdidscrollを利用して実装したほうがいいかもしれません。



とはいえ、そこまで複雑でないアニメーションであれば、
IFTTTAnimationを実装しても、scrollViewのdelegateをオーバーライドして実装すれば
応用が効きました。

実際やってみたのは、ページ単位で自動発生するアニメーションをios7から実装されたUIKitによる
キーフレームアニメーションで実装し、同じオブジェクトにIFTTTAnimationをセットしても
特に問題なく動きました。


viewのalphaやらx座標やらが結構ややこしくなってくるので、そこらへんをしっかり管理すれば、
簡単なアニメーションと組み合わせて非常に効率よくチュートリアルを作れるんじゃないでしょうか。




1年もしないうちにこのUIが古臭くなる恐怖を覚えつつ・・・。

2014年9月4日木曜日

他社の通信の解析。自分メモもかねて。

チームメンバーにスーパーハカーがいます。

その方の共有なのですが、
他社のアプリがどういう通信を行っているか解析する方法(httpsは不可)
です。

1.ここを参考にMacをアクセスポイント化します。 http://weekly.ascii.jp/elem/000/000/136/136392/ 

2.テスト端末をアクセスポイント化したマックのWiFiにつなげます。 

3.Wiresharkをインストールして起動&Analyze開始 


すげーwww

これで今はやりの白猫解析を行ってもらった結果

- 素材DLとゲーム処理は別サーバーに分けている 
- ゲーム処理はAWSのTokyoリージョンで処理 
- 素材はAkamaiのCDNを利用 
- 暗号化はHTTPSを使わずに独自の暗号化処理を用いている(おそらくSSLによる負荷を気にしての措置) 
- Nginxは使っておらず直接Apacheにアクセスしているっぽい。たぶんPHPなんだろうな。



めっちゃ勉強になります!

2014年9月3日水曜日

Facebookとかが公開IDをどうやってつくってるのか

http://qiita.com/daisy1754/items/98a6e6b17d8161eab081

ここにまとまっているんですが、
プチすごいのがFacebook。

一種の発想の転換ってやつだなって思いました。

一般的なのはInstagramあたりのやり方なんでしょう。
また、さらに簡単なのもあって、
phpならuniqidというメソッドを使ったあれやこれやでしょう。

ただ、せきゅりてー的にどうなんとかあり、各社独自のプログラム組んだりするわけです。

これは裏側に、
リアルタイムに独自のロジックでユニークかつランダムな文字列を生成しなければならない
という事情がありまして、負荷とかできるだけかからないように作らなければならないんです。
(これが意外とやっかいちゃん 理由は最下部で)


そこでFacebookの手法。

リリース前とかに一気に300万件とかかぶらないID作っておけばいんじゃね?

ユーザーいねーから負荷かかってもいーじゃんね。



その発想はなかったわー。



まさにこれを実装しているんですが、
ぱぱっと作って300万件レコードつくってみたら
ロングフリーズ発生してそのまま帰ってこなかったのはナイショ。




ちなみに、ユニークかつランダムな文字列を負荷がかからないように作るのが
なぜやっかいちゃんかというと、

123abc という文字列から3つランダムに取り出して並べる

って作業をします。

すると、 b2a という文字列が出来ます。

これをテーブルAに登録しておきます。

テーブルA:[b2a]

さて、もう一人ユーザーが増えました。

また例の文字列つくらにゃあかんですね。

さっきのロジックで作りましょう。

3ba という文字列が出来ました。

登録。

テーブルA:[b2a,3ba]

順調、順調。

またまたユーザー登場。

b2a という文字列出来た。

とうろ・・・ できねー!

かぶってますね。

これ回避するために、かぶってるチェックしなきゃあかんすね。

これは二人目のときからどげんかせんといかんやつだったのですが、
二人目が 3ba 作った時に一回テーブルAにアクセスして
3ba かぶってない?大丈夫?
って聞かないといけません。

セーフならそのままいっちゃってー
アウトならもっかいランダムで作り直すわ。

これが100万人目とかなったら。。。
イメージできました?
大変そうです。


細かく言えばいろいろあるんですが、
ざっくりこういうことなんでやっぱFacebookの発想おもろいです。

2014年9月2日火曜日

UIチームができる理由

わかる気がします。

造っている中で、あれが欲しい、これが欲しいってのは当然出てきて
当然それはユーザーに基づいて考えるわけですが、
では、
全て叶えてあげればユーザーにとって至極のものが出来ます!
ということはないです。

サービス全体を見る。
これにつきます。

UIを理由に~という機能をつけない

この意見は最初反対でした。
しかし、これを割り切れることがユーザーがより使いやすいサービスを
産み出すことにつながることが理解できました。


具体的には、例えばボタンの位置と遷移のアニメーションの関係。
~の機能を追加するには8割それを起動するボタンが必要になるはずです。
そして、その機能が起動した後はこれまた8割は画面に変化があります。

ボタンを押す⇒画面が変化

まずこのワンアクションがユーザーに違和感を与えないか、
そして、ここに至るもしくはここから至る経緯で違和感を与えないか、
これは画面の変化のアニメーションに大きく影響しているなと感じています。



さらにここにユーザーのアクション(スワイプ等)が絡み合ってくるでしょうが、
まずは遷移のアニメーションから。


そして、これからの遷移のアニメーションには
InteractiveTransition
これです!

詳細はまた。

2014年8月28日木曜日

CertificateがRevokeもDownloadもできない!

数時間はまりました。

ぐぐってもぐぐってもわが暮らし楽にならざり、じっと白猫を見る。

結論としては、どうやら開発者登録自体の期限がせまってるのでContactしてください。
まずはそこから始めましょうということでした。

確かに、Certificateだけじゃなくて全てのアクションができませんでした。

わかりにくすぎるだろw

Warningで書いとけよw

p12の12ってなんだよ!



provisioningファイルを作成するフローは毎回・全員はまりますね。

Appleさんわかってますか?

2014年8月6日水曜日

LINE連携で少しはまった

いろんなサイトに

NSString *url = [NSString stringWithFormat:@"line://msg/text/%@",text];
NSURL* lineUrl = [NSURL URLWithString:url];
[[UIApplication sharedApplication] openURL:lineUrl];

canOpenURLは一旦無視したとして、だいたいこれでいけるよって書いてます。

ウソですね。

ちゃんとテキストをURLエンコードする必要があります。

NSString *url = [[NSString stringWithFormat:@"line://msg/text/%@",text] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

これ。


以前はさらにURIEncodeを確実に行うために、

(NSString *) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                 (CFStringRef)str,
                                                                                 NULL,
                                                                                 (CFStringRef)@"!*'();:@&=+$,/?%#[]",
                                                                                kCFStringEncodingUTF8);

ここまでやっていました。
ARC使う場合はさらにややこです。。。


めんどくせw

2014年7月30日水曜日

覚えておくと力強いiOS開発の概念・用語

ぱっと思いつくやつを。


・View・ViewControllerの階層構造

iOSの画面の作りが基本的にどうなっているかというもの。
ViewControllerというのはその名の通りそれだけでは何かを表示するものではありません。
その上に様々なViewが重なっていて、それらを管理しているものです。
また、様々なViewControllerには一番根底となるViewが存在しそのViewに対してButton等のViewをaddsubview(viewの追加)するわけですが、

Androidとは違って、多くの人々がイメージしているlayer構造に近いかと思います。


・UINavigationController

OpenGLとかで開発していない限り、だいたいこれが根底にいます。
画面遷移にあたることも管理してくれており、大別して、

・push 画面を上に重ねる感じ(結果次ページに遷移する動作)
・pop 上に重ねた画面を捨てる感じ(結果戻る動作)

があります。というかだいたいこれで遷移は完結できます。

他にもこのControllerにはNavigationItemやらNavigationButtonやらがデフォルトでついてます。
よくあるUIの最上部の44pxあたりの領域のことですね。


・UITabBarViewController

まだまだ現役UIで、下部に何個かボタンが並んでいるUIです。
Facebookアプリなんかは現在これにあたります。

一つ一つのボタンがUIViewControllerをもっているのが通常の作りで、ボタンを押すとそれが切り替わります(画面が切り替わる)。

これと上記のUINavigationControllerを組み合わせることができますが、
少々やっかいな動作をみせることがあるのでお気をつけください。


・plist

property listのこと。中身はただのxml形式なんですが、xcodeでわかりやすく編集ができます。
string,array,dictionaryをサポートしており、定数をおくDB的な感覚で使えます。


・info.plist

プロジェクトに直結したplist。BundleNameやUrlSchema,デフォルト言語など、様々なデフォルト設定ができます。


・Localizable.strings

ローカライズ対応が容易にできます。
NSLocalizedString(KEY,nil)


・Deligate

移譲するという意味。例えば上記のViewController間等で使われ、Classをまたいで命令をしたりする。


・AppDeligate

アプリの親玉のようなクラス。アプリ起動時等の肝心要なところをつかさどっている。



とりあえず、ここらへんのもうちょい詳細を知っておくとエンジニアとの会話がスムーズになること間違いないです。

Facebook連携

見事にハマりました。

はまった大きな要因が、ググって出てくる古い情報。
そもそも最新を追え!ってことなんですが。。。

Facebookログインの仕様変更により、Permissionの解放が厳しくなりました。

で、いままでのようにbirthdayなんかのPermissionをログイン時に許可とろうとすると、
エラーレスポンス返されます。

エラーの原因を調べていてぐるぐるしてましたが、
なんてことはなくFacebookからPermission使用許可を取得しないといけないということでした。


アップルのようにアプリを審査してもらう必要があります。

Permissionによっては14日もかかるだとか。





誕生日ぐらいよくね?w

2014年7月10日木曜日

tableviewやcollectionviewでcellに画像を非同期で表示する場合

これが昨今利用シーンの多いこと。

一覧性を重視しているUITableViewやUICollectionViewでは当然のことかと改めて気づかされました。

注意点は至極簡単、

collectionView:cellForItemAtIndexPath:等のデリゲートメソッドで
imageview.image=nil
をして非同期で持ってくる画像を毎回初期化してやることです。

二つのViewはcellを再利用するという便利な機能がついていますが、
それゆえに非同期で画像を表示しようとすると、
表示したいindexがずれてしまうことがあるのです。
再利用された際に次の画像が表示されるまで前の画像が残ってしまうんですね。

これと collectionview:didEndDisplayingCell:forItemAtIndexPath: とかで
cellの画像を初期化するのを併せて行うといいのではないでしょうか?


collectionViewの造りに日々感動しております。




最近プログラミングのロジックの勉強を改めてしたいなぁと漠然とおもっとります。。。

2014年7月3日木曜日

Blur効果

blur = かすんだ
とかいう意味。

曇りガラス風とかいったりします。

ios7からやたらAppleがプッシュしてますね。
ios8をちょっといじりましたが、猛プッシュ。
透過が効いているところは、ほぼ全部ブルアってます。
xcodeまでブルアってて「いる?」ってなりました。


これ、実装が大変なんです。

Appleがソースを提供してくれないせいで、
ほぼ自前実装になるんです。(と思っていた)

ios7時点でUINavigationBarとかデファルトでブルアってるんですが、
[UIView setBlur:0.8]
みたいなことはできません。

一昨年はこのBlur効果を使用するため、
UINavigationBarを無理やりUIViewとして使うみたいな方法をしていた人がいたそうなのですが、
見事リジェクトされたそうです。


ここで驚愕の事実。


この記事を書いている際に、改めてBlurについていろいろと調べてみたら、


現在ではWWDC2013にてアップルがサンプルソースを提供してくれているため、
それを使用するのが簡単です。

https://developer.apple.com/downloads/index.action?name=WWDC%202013

UIImage+ImageEffects でcategoryとして提供されています。

もっと様々な傾斜をかけようとしたら、やはり自前実装ですね。

裏のキャプチャとって加工してはりつけたり。


という事実が発覚。

今日まで上記のアップルサンプルを知らずに、めんどくさい処理やってました。
絶望しました。。。




気を取り直して、

最近はparallaxな効果に興味がでてきて、実装してみたものの周りの評判がワルめ。

デスヨネー!


2014年6月30日月曜日

新サービスを立ち上げる企画者へ

梅雨の終わりが近づき、夏の暑さが顔をのぞかせ始めた今日この頃。
体調を崩さずに楽しく仕事をしていらっしゃるでしょうか?


iPhoneアプリを開発する際にリサーチは当然すると思われますが、
他社のサービスのリサーチの前にまずやってほしいことがあります。

Apple純正アプリのリサーチ

です。

なぜかというと、

Apple純正アプリのUIは実装するのに工数がそれほどかからない

からです。

開発は当然限られたリソース内で行う方が多いと思います。
その際にこれが効いてきます。

純正アプリのUIは好き嫌いあれど、多くのユーザーが使います。

これだけの規模使用されるとそれはもはやUXにも影響してきます。

よって、時間をあまりさけないUI等にはこの純正UIを用いるのが
とても効果を発揮するでしょう。



同様に、こういうサイトも参考にしていただけると開発者嬉しいですね。




さらにさらに、Appleの基本ViewControllerとかUIKit系を抑えていただけてると
もはやエンジニアの羨望の目を欲しいままにできるのではないでしょうか。


副産物として共通言語もでき会話もスムーズになります。
「UITabBarViewControllerのtabIndexが3の挙動おかしいよ~」
とか。
ないか。。。



若輩者のエンジニアより

2014年6月27日金曜日

UIPageViewControllerについて

電子書籍アプリのようなUIをつくる際には最適なViewController。

ただ、私が現在手掛けているアプリでは少々特殊なUIを採用しているため、
このViewControllerをベースにしています。



使っていて気付いた点

良い点
・複数のViewControllerに気持ちいいスクロール&ページングを実装するにはお手軽。

悪い点
・汎用性が低い




基本的な実装方法は

全体の親となるViewController(Navigationとかにしとくと楽)に
UIPageViewControllerをのっける。
あとはPageViewControllerのライフサイクル内で最初のページとなるViewContorollerをセットし、
UIPageViewControllerDelegateメソッドの

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
 viewControllerBeforeViewController:(UIViewController *)viewController;

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
 viewControllerAfterViewController:(UIViewController *)viewController;

にて、前ページ、次ページのViweControllerを返すようにするだけです。

ここで、UIPageViewControllerを使用する際に、ほぼ確実に必要となるページ数の概念なんですが、
これがやっかい!

ページ数の管理を上記二つのメソッドだけで管理しようとしてハマりました。

どうやら上記二つのメソッドは、
初回にめくろうとしたタイミングでafter(before)のほうが二回呼ばれます。
これはページをめくった段階でさらに次のページまで生成してくれるからです。

これが落とし穴でした。


例えば、この二つのメソッドでページの管理をすると最初を0ページ目として、
afterに++、beforeに--を設定しておきます。
すると、1ページめくった際にLogをみてみると
0
1
2
となってしまうわけです。


解決方法

UIPageViewControllerを使用すると、どうしても内包するViewControllerで自分のページ数が必要になります。
これとさきほどの問題点を併せて、
上記二つのメソッドでViewControllerを作成しreturnする際に、各ViewControllerにページをセットしてやります。これで自分のページ数は解決。
さらに、このままではUIPageViewControllerのほうのページ数がずれたままなので、

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed;

これを使います。

これは読んで字のごとく、スクロール(ページング)のアニメーションが終了したタイミングで呼ばれます。ページングなので途中で話してページが戻った場合にも対応できます。
if (completed) {
  UIViewController *vc = [pageViewController.viewControllers objectAtIndex:0];
  pageIndex = vc.pageIndex;
  
  いろいろ
}

としておけば、めくりが終了した段階でUIPageViewControllerに現在表示されているページ数が設定されるわけです。 [pageViewController.viewControllers objectAtIndex:0]の書き方がものすごい気持ち悪いのは置いておきましょう。

これで基本的なUIPageViewControllerの使い方は網羅できたのではないでしょうか。


汎用性が悪いと書いたのは、まだまだこのUIPageViewControllerを使ってハマった点があるからです。
そのほかのハマった点と解決(逃げ)策はまた後程。






最近、人生初めて世に言う「ブランドもの」なるものを買ったのですが(9万円ほどのジミーチュウの財布)、買い物欲みたいなのが少しわかった気がします。
高い買い物をした際のえも言われぬ高揚感は、人間の生理的欲求のどれにも属さないかつ物欲とも若干異にするなにかしらの快楽が確かにあると感じました。

「欲」についての勉強をしたくなりました。

2014年6月26日木曜日

iPhoneアプリのメモリ管理のお話し。(ARC使用)

チームメンバーの方がメモリ調査をした結果わかったことなのですが、

「block関数内ではデフォルトで強参照してしまう」

です。

これはどういうことかというと、

self.abCallback = ^{
  [self amethod];
};

こういう事例でselfがabCallbackを強参照し、abCallbackによってselfが強参照化されてしまうので、
循環参照が起こりメモリが解放されません。

この場合は、

__weak typeof(self) blself = self;
self.abCallback = ^{
  [blself amethod];
};

と弱参照にしてやるのがいいようです。

また、これは、ブロックに限らずdelegate等でも起こりがちなので、
常に所有関係を意識するのが大事です。



全然関係ないですが、男女も弱参照ぐらいがちょうどいいと感じています。
強参照で循環参照とか恐ろしすぎて。。。

2014年6月18日水曜日

はじめに

iOSの開発を業務として行うのは初めてなプログラマーの視点で、
プロジェクトとして各立場の方々がiPhoneアプリの開発を行う際に

プログラマーはこう考えている
こういうUIを作る際に困った
プロジェクトとしてこういうことに困った
etc

という内容のことを思いついた、思い出したタイミングで
連ねていきたいと思います。

なんらかの方法でこの記事にたどり着いた方々は
暖かく見守りつつ、ご指摘いただけると助かります。