360|idev にきています(1日目)
360idev(すりーしっくすてぃ あいでぶ)
Home - 360|iDev
2009年から続いているiOSの大きなカンファレンスで、アメリカでは結構有名みたいです。会社に「行かせてちょ!」と言ったら快く行かせてくれました。めったにない機会だと思うので、いろいろ吸収してきたいと思っています。
こちらはネームプレート。しっかりしていて感動。。! !
今日(日曜)参加したセッション
今日は大きなセッションが午前と午後それぞれに4トラックずつあるような形でした。 迷ったんですが、個人的になかなか理解が深まらないUI系の2つに参加してきました。 参加してみたらどちらも手を動かすワークショップ形式で、時差ぼけの影響もあり、初日からぐったり。
以下、雑ですがとりあえず情報発信ということでご容赦ください。
Universal Layout Workshop
http://360idev.com/sessions/universal-layout-workshop/
講師は@iwantarealname さんで、iOS8 Day-by-Dayとか書いてる人でした。 Auto Layout、Adaptive Layout、StackViewと、それぞれポイントを押さえた解説で3時間半があっという間でした。 後半時差ぼけがひどくて頭回らなくて後半ついていけなかった部分があり悔しい。。
こちらはセッションで使用したサンプルアプリ。
以下、メモ。
- Auto Layoutはみんなだいたいわかるよね的な進行。
- よくやるcontrol + drag で制約選択するやり方より、IB右下のアイコン(Pin menu)からまとめてつけちゃったほうが楽だよ、という知見。
- Adaptive LayoutはiOS8から出たやつで、iOS9では大して変わってないよ。
- iPhoneのLandscapeがCompact/Compactなのはたぶん、横書きだと横スクロールつらいから、同じ幅でもRegularにはならないんだと思う、みたいな知見
- Content Hugging Priority を低くすると縮まるor広がる(結構ここは難しくて講師も一瞬ハマってた。)
- はい、いまAutoLayoutで組んだものをStackViewで置き換えましょー。
- StackViewはサイズの計算にintrinsic content sizeを使うので注意。imageView画像とかがあるとそのサイズから勝手に計算するよ。
- IBでStackViewを使うと、AdaptiveLayoutがめちゃくちゃ簡単。全くコード書かなかった。
- StackViewをアニメーションで表示非表示させる場合とかは、コードを書く必要が出てくる。
- arrangedSubview(この辺力尽きてた。あとで復習必要。)
午前中セッション前半終わり、休憩中。IBでのAutoLayoutとAdaptiveLayoutの実装方法についてワークショップ形式で学んでいます。実際に手を動かすと違いますね。異なるSizeClassに対してAdaptiveにLayoutしたの初めてかも。
— ぼくごじら@360|idev (@toshi0383) 2015, 8月 16
上に貼ったサンプルアプリはコミットがわかりやすく切られているので、興味あるひとはいろいろ動かしてみると勉強になると思います。
POWER UP YOUR ANIMATIONS !
@icanzilb さん。
Marin Todorov
AltConfでやっていたのと同じタイトルでした。 発表で使ったアプリも公開してくれるらしいんですがまだなので、AltConfのほうを一旦貼っときます。
https://realm.io/jp/news/altconf-marin-todorov-animations/realm.io
今回の内容はAltConfのからさらに新しいネタが満載でおもしろかったです。
さすが匠の技という感じで、ほんの半日でかっこいいアニメーションがいくつもできあがりました。 EasyAnimationというライブラリの作者の人みたいです。
このライブラリを使うと、アニメーションの実行をチェーンでつなげることができたり、
Repeatさせてるアニメーションをキャンセルしたり、
CALayerの変更をアニメーションさせたり(UIView.animateWithDuration~だと普通はできない)することができます。
Appleに用意しておいてもらいたいくらいのかゆいところに手が届いているライブラリです。
iOS Animations by Tutorialsという本も執筆されたそうで、英語なんでアレですが入手して頑張って読んでみたいと思います。
http://www.underplot.com
余談
デンバーについての情報をいくつか。
- デンバー国際空港がインディオ推し
- 基本的に乾燥していてすごしやすい。夏なのに虫とか全然いない。雪もほとんど積もらないらしい。
- 街の大きさは、田舎の都会という感じ。仙台とか?道は全然混んでなくて快適。(休日だったからみたい。月曜は夕方ちょっと混んでた。)
- クラブなどナイトシーンも賑わっている模様。
- 毎日帰る時にホームレスのメッカを通り過ぎるんだけど、Uberの兄ちゃん曰く "They are nice."
- タクシーはあまり走ってなくて、バスや電車以外だとUberしかない気がする。
ひとまず速報なんでまとまってないですがこんなところで。
2日目も行ってきます!今日も気が向いたら速報を書きます!
最後に宣伝
第1回 カジュアル Swift 勉強会 @ 青葉台で発表してきました
SwiftをObjective-Cと一緒に使うことについて発表してきました。
最後のオチがひどいんですが、まあうまく交渉がまとまればいいなあ、と思っています。
上のスライドにもちょっと書いてますが、iOS7対応をしようと思うと、他のSwift製ライブラリをstatic libraryやdynamic frameworkの形で直接インポートできないので、せっかくのネームスペースの良さが生かせないというのがありますね。
たぶん直接ソースコード突っ込めば使えるんでしょうけど、internalな名前が衝突しそうです。
熊谷さんが .frameworkを読み込ませる .a を作ればイケますよと言っていたのだけど、どうやるのかな。
勉強会は、積極的に意見を出す人が多くて、学びが多かったです。
私とか結構資料作っていったんですけど、簡単なテーマをぺろっと出してあとは談笑とかでも十分楽しめそうでしたね。
Javaとかは割とやり方が業界標準として決まってる感がありますが、Swiftは言語的にかなり自由にいろいろな書き方ができるので、議論は尽きないと思います。
他の言語に詳しい方もいて、「Goではこうなってるんですよ」とかすぐに例が出てきて、盛り上がりました。
余談ですが、青葉台は以前嫁が住んでいた頃によく行ってたので、久しぶりの地元、という感覚で懐かしかったです。
当日は花火大会が各地であったようで、浴衣の人をよく見かけました。
夜の懇親会の店は結構美味しかったので貼っておきます。
今週の進捗:React.js
さて、NodeSchoolで基礎力もアップしたことだし、今週末も引き続き嫁そっちのけでReact.jsで作ったサイトをいじくり回した。
前の記事を書いてから進歩した点
browserifyを使って依存関係を解決!
ひとつのjsファイルにまとめてそいつをuglifyjsで難読化した。
サーバサイドレンダリングを導入するまでには至らず。
browserifyはこうやっている。
browserify -t reactify public/src/app.jsx | uglifyjs > public/build/bundle.js
browserify reactify とかで検索すると、いきなりgulpfile.jsのサンプルを載せてる記事がたくさんヒットするんだけど、そんないきなりgulpなんて使いこなせないし。。
ので、まずは自分のjsファイルにひとつずつbrowserifyコマンドを適用して吐かれたエラーを見て対処した。コマンドの安心感。
しかしgulpもbrowserifyも、エラーメッセージが不親切だった。
toUpperCase is not a function
ってコンソールに出て、30分悩んだらコンポーネントをmodule.exportsしていなくて要するにぬるぽになっていただけだったとか、そんなのばっかりだった。
あと結構ウェブで拾ったpackage.jsonをコピペしちゃうんだけど、バージョンが古かったりして依存関係おかしくなるので、自分でnpm install --save hoge
とかしたほうがいいんだと思う。
ページングを実装した!
ライブラリも幾つかあったんだけど、どっちみち学習コストありそうだったので自分で作った。
クロージャの変数スコープについてよくわかってなくて焦った。
そんなところかな
なんかやってることがしょぼい!笑
まあこんな調子でのほほんとやっていきたいと思います。
NodeSchool International Day in Tokyoに参加してきた
NodeSchool International Day in Tokyo
諸事情で途中からの参加になってしまったけど、みんなモクモクと作業していたので問題なく溶け込めた。
functional javascript workshopは前にちょっとやっていたんだけど、今回はjavascripting とかlearnyounodeとかちょこっとかじった。
基礎を学ぶのって意識しないとなかなかやらないから、いい機会だった。
ありがたい。
ちょっとLTで前の記事に書いたことを喋らせてもらったんだけど、準備が間に合わずぐだぐだになってしまった。
5分を甘く見ていたせいで、自己紹介だけでほぼ終わった。申し訳ない。
それでも懇親会では周りから反応をいただけたので収穫ありだった。
やはりアウトプットは大事だと思う。
その他の所感としては、
- 小学生くらいの小さい子が来ていて、「セミコロン?」とか言ってるのがめちゃくちゃかわいかった
- オープンな雰囲気でよかった。暖かい日だったし、夏期講習みたいな気分だった
- マークシティの構造がわけわかんない
- そういえば世界各地の会場ともつながっていたみたい。世界規模でやってるなんて、すごい話。
といったところ。
次回は夏らしいのでまたまったり参加したい。
GWなのでReact.jsでイベントサイトを作った
http://jam-navi.herokuapp.com/
イベントといっても音楽関係でしかもジャムセッション縛りという割とニッチなサイトを作った。
ざっくり
とりあえずリリースすることが最優先だったのでサーバサイドレンダリングとかはなし。Fluxとかも知らない。けど、「投稿したものがタイムラインで流れてくる」というのはReact.jsと相性が良さそうだと直感して使ってみた。
ルーティングはreact-router使ってる。が、ログイン画面からホーム画面への遷移とかは window.location.href = "/"
みたいにして全画面読み込みしてる。子供から子供への遷移がうまくいかなかった。
サーバサイドはNode.jsで、バックエンドとしてParseを使っている。
Node.jsでのアプリは2つ目で、ちょっとずつ慣れてきたところ。
Javascript書いててハマったポイント1: this
みんな言ってるけど、thisがすぐ迷子になる。
あーハイハイって言ってbindすればいいんだけど、thisよ。。という気持になる。
これはRegister Success! って1度出して3秒後に(突如)消す、というコード。
.bind(this)
がないとsetState
なんてfunctionはねえ!と怒られる。
セミコロンはなくてもいいんダネ!
var successDialog if (this.state.postSuccess) { successDialog = this.getPanelInfo("Register Success!") var timeID = setInterval(function() { this.setState({postSuccess:false}) clearInterval(timeID) }.bind(this), 3000) }
Javascript 書いててハマったポイント2: 依存関係の解決方法
「よーし、サーバサイド脳だ!」という頭で var hoge = require('hoge')
などと書いたらブラウザで動かなかった。
requireはブラウザでは使えないんだって。どうやら、browserify とかいうのをかませればrequireで解決した依存関係をなんとかしてくれるみたいだ。
結局今回は親のhtmlに<script>
を貼ってスコープ内にクラスを展開したけど、これって全クラスに対してフルオープンになってしまっていて微妙なんだと思う。
それとも、browserify使っても一緒なのだろうか。ちゃんと調べ切れていない。
React.js でハマったポイント1: jsxの記法
例えばclass属性を指定したい時、このように書かなければならない。
<div className="col-lg-6">
そしてstyle属性を指定したい時、このように書かなければならない。
<div className="panel-heading" style={{float:'right'}}>
jsx記法でclass="hoge" と書くと変換する時に無視される。
「ここはこのソースコードコピペでいけるはず!よし!」とかやってたらうまくスタイルが適用されなくて実はclass属性がjsxに無視されてたとか何度かやった。
もちろん、React.jsの生のソースを書いてもいいわけだが、このあたりhtmlと混同するし、例えばデザイナーとの分業みたいなことも難しいというか無理だと思った。
まあ弊社でデザイナーさんとコードレベルで連携することはこれまでなかったので個人的には別にいいのだけど。
一方例えばロジックをhtmlに埋め込むみたいなことは直感的にできたので、これは使いやすいなと思った。
<div className="hoge"> <foo /> {successDialog ? successDialog : null} </div>
このようにsuccessDialogに値がある時だけタグを吐き出す、という書き方ができる。
これは別にこうしろとどこかに書いてあったわけではないけど、ちょっとしたダイアログの出しわけみたいのはこれでいいやと思ってやってる。
まとめ
Reactっぽいのはイベントの登録と取得の部分。
2秒ごとにpollingしてるので、イベントがどこかから登録されると自動的に一覧に反映される。
ページングとかまだ入れてないのでほんとまだよちよち歩き状態。
一覧と登録の機能だけなので、ほとんどチュートリアルを見ながら作れたけど、React.js は思ったよりは学習にコストがかかることがわかった。
どこかの記事でRiot.js 簡単でいいよとか書いてあった。
ちなみにParseの無料枠には 1秒間に30リクエストまで という制限がある。
2秒に1回pollingしてるということは、例えば60個くらい同時に窓を立ち上げられたらこちらはお手上げである。
読者諸君の良識ある行動に期待している。
javascriptとSwiftでArray#reduceを自分でも実装してみた話
最近1年くらいQiitaにばかり書いていましたが、こちらではもう少し日記みたいな感じで徒然と書いていこうと思います。
さて、今日はちょっと趣味でjavascriptの勉強をしようと思いました。
これまでjsは真面目に書いてこなかったのですが、とりあえずとっかかりにと思ってfunctional-javascript-workshopというのをやってみています。
Functional Javascript
まだ18 challenges中7個目ですが、既にreduceを再帰で実装しましょうという課題が出てきました。
こういうのやってると新人研修を思い出します。
私の場合回答はこんな感じになりました。
/* @flow */ module.exports = function reduce(arr:Array<any>, fn:any, initial:any):any { var reduceOneFn:any = function reduceOne(index:number, value:any):any { if (index > arr.length - 1) return value return reduceOne(index + 1, fn(value, arr[index], index, arr)) } return reduceOneFn(0, initial) }
せっかくなのでFlowtypeで型チェックをしながらやっています。ちなみにGitHubが出しているatomというエディタだとFlowtypeのpackageをいれればリアルタイムで型チェックをさせられるので便利でした。
上の例だとanyばっかりであまり型チェックが意味をなさなくなってますが。。
ジェネリクスを使ってFlowtypeに型チェックをさせようとするとなんだかうまくいかなかったんです。
なんだかモヤッとしたので、型に厳格な例の言語でやるとどんな感じになるのか、やってみました。
Swift
extension Array { func reduceAFn<U>(index:Int, value:U, combine:((U, T, Int) -> U)) -> U { if index > self.count - 1 { return value } return reduceAFn(index + 1, value: combine(value, self[index], index), combine: combine) } func reduceA<U>(combine:((U, T, Int) -> U), initial:U) -> U { return reduceAFn(0, value: initial, combine: combine) } }
ジェネリクス使えるよ。そう、Swiftならね。
SwiftのArrayの宣言部分ではすでに型引数 T が宣言されているので、extension内でもそのまま使うことができました。
他のところは自分で U という型引数を定義しています。
なおSwiftではローカル関数内でローカル関数自身を呼ぶことができないという制限があり、reduceAFnを外だしせざるを得ませんでした。
ユースケースとしてはこんな感じですね。
// 配列の中身を全部足す var r = [0,1,2,3,4,5].reduceA({(prev, current, index) in return prev + current}, initial: 0) println(r) // 15 // 単語の出現回数を数える var r1:[String:Int] = ["hello", "hello", "yellow", "yellow", "yellow", "foobar"].reduceA({(prev, current, index) in var countMap:[String:Int] = prevv countMap[current] = (countMap[current] ?? 0) + 1 return countMap }, initial: [String:Int]()) println(r1) // [hello:2, yellow:3, foobar:1]
再帰的な書き方って、人に説明するのもされて理解するのも難しいんですが、問題が解けたときの満足感はなにものにも代えがたいものがありますね。
ひとまず眠いし今日はこんなもんで。