【swift】nilとoptionalな型の取り扱い
nilの扱い
swiftでは通常、変数や定数にnil
は代入できません。
var hoge: String = nil let fuga: String = nil
これはコンパイルエラーになります。
nil
を代入するためには、optionalであることを宣言するために型に?
をつけます。
var hoge: String? = nil let fuga: String? // 代入しなくても初期値はnil
メソッドなどを使用する際
変数や定数をoptionalな型として宣言するということは、
「必ずしも値が入っているとは限らない(nilである可能性がある)」
ということです。
その状態でメソッドを叩こうとすれば、当然nil
だった場合は実行できません。
let str: String? str.uppercaseString // strはnilの可能性があるのでコンパイルエラーになる
コンパイルエラーにならないようにするためには、変数や定数の後ろに!
をつけるとコンパイルできるようになります。
let str: String? str!.uppercaseString // コンパイルは通るようになるが実行時にエラーになる
ただ、このケースだとコンパイルは通りますが、str
はあくまでもnil
なので実行時にエラーになります。
この場合str
がnil
でないことを事前にチェックする必要があります。
let str: String? if str != nil { str!.uppercaseString // strがnilではないのでメソッドを実行することができる }
この辺りの記述をもっとスマートに書くために、Optional BindingやOptional Chainingなどの記法がswiftでは提供されているのですが、それについてはまた別途まとめます。
【swift】InterfaceBuilderを使用してViewControllerを組み立てる
objective-cと変わらないと思ってたらちょこっとだけ違いました。
新規ファイル作成から「Cocoa Touch Class」を選択して
「Also create XIB file」にチェックを入れれば、ViewControllerのファイルと一緒にxibファイルを作成されます。
objective-cであれば、initWithNibName
で初期化しなくてもInterfaceBuilderで作成した画面が適用されていたのですが、swiftの場合はnibName
は必ず指定しないとダメっぽい?
self.window?.rootViewController = TestViewController(nibName: "TestViewController", bundle: nil)
【swift】変数・定数・関数を定義する
最近swiftをちょっと勉強しだしたので、ちょっとずつメモを取っていこうと思います。
変数
var hoge: String = "hoge" // 型を宣言する var hoge = "hoge" // 宣言しなくても自動的に判定もする var hoge = "hoge", fuga = "fuga" // カンマで連続で定義することもできる var hoge, fuga: Int // 複数の変数を型宣言することもできる
型宣言は省略することのメリットよりもデメリットの方が大きいので、必ず宣言するようにする。
定数
let HOGE = "hoge"
関数定義
// 返り値がある場合 func say() -> String { return "hello." } // 返り値が無い場合 func say() { println("hello") } // 複数返り値がある場合 func say() -> (Int, Int, Int) { return (1, 1, 1) }
GoogleAnalyticsのトラッキングのコールバックを設定する
〇〇ページに遷移するためのボタンのクリック率とかを図るためによく、ボタンのクリックイベントを計測したりします。
でも、このページ遷移とトラッキングのAPIを同時に叩くと、やっぱりうまくトラッキング出来ないこともチラホラあるみたいです。
Analyticsのページを見ても、明らかに少ないよなーこの数字っていう時が結構あります。
なので、トラッキングのAPIが終わってからページ遷移したいんです。
こういう要望のために、Analyticsはちゃんとコールバックを設定できる様になっています。
hitCallbackを使う
ga.js
もanalytics.js
も基本的には使い方は一緒で、hitCallback
というkeyで関数を指定します。
// ga.js _gaq.push(['_trackPageview', { page: '/index.html', hitCallback: function() { alert('complete!!'); } }]); // analytics.js ga('send', 'pageview', { page: '/index.html', hitCallback: function() { alert('complete!!'); } });
pageviewのAPIが完了してからhitCallback
で設定した関数が実行されます。
注意点
GoogleAnalyticsのjsが読み込めないと正常に動作しないため、コールバックでページ遷移をする処理を書いていると、ページ遷移しないボタンが出来上がってうので注意が必要。
【Ruby】ActiveRecordのAssociationにメソッドを追加する
ActiveRecordのhas_many
とかbelongs_to
とかのAssociationはブロックを渡してメソッドを追加することができます。
class User has_many :blogs do # ステータスがopenのものを取得する def open where(status: 'open') end end end
こんな感じで、ブロックの内部で関数を定義するとその関数をメソッドチェーンで実行できるようになります。
User.first.blogs.open
複数のモデルで使い回したい処理がある場合は、moduleにまとめてextendオプションでメソッドを追加することも可能です。
module Common def open where(status: 'open') end end
class User has_many :blogs, extend: Common end
配列にして、複数のmoduleも渡せます。
class User has_many :blogs, extend: [Common, Common2] end
便利ー!!
【Rails】belongs_toで紐付けたモデルの存在チェック
belongs_to
で紐付けたモデルが本当にデータとして存在するかどうかをチェックする。
class Blog has_many :comments end
class Comment belongs_to :blog end
例えば、このようなモデルがあった時、Blogモデル経由でCommentを作成した場合は、すでにBlogは存在しているので、comment.blog_id
には確実に存在しているBlogのIDが入ります。
Blog.first.comments.create # 存在しているブログからコメントを作成する
ですが、Blogモデル経由ではなくCommentを直接作成するとき、Blogと紐付けるためにはBlogのIDを外側から指定しないといけません。
Comment.create(blog_id: 1) # コメントの作成時にblog_idを指定する
この方法で作成する時、特に設定しないままだと存在しないBlogのIDも指定できてしまいます。
Comment.create(blog_id: 999) # IDが999のBlogは存在しないが、Commentは作成できてしまう
参照先の指定したIDのデータが存在しない場合にエラーを投げるにはValidateを設定する必要があります。
class Comment belongs_to :blog validates_presence_of :blog end
validates_presence_of
で対象を指定すれば、参照先のデータが存在しない場合はエラーになり、データは作成されなくなります。
【css】floatとvertical-alignを併用しようとしてがっつりハマった話
先日書いたブログに、先輩がこんな風にコメントしてくれたにもかかわらず、がっつりハマったので戒めのためにもメモしておきます。
なにが起きたか
要件としては、高さの違う2つのボックスを横並びにして、上下中央寄せにする、というものでした。
<div class="wrapper"> <div class="left">左は<br>二行</div> <div class="right">右は一行</div> </div>
.wrapper div { float: left; }
とりあえず、横並びだからfloatを指定して、上下中央寄せはvertical-alignを使えばいっかと思っていたら、全然そんなことなかった。(ちゃんと仕様を理解しないでなんとなく使っているからこうなる)
.right { display: table-cell; vertical-align: middle; }
とか指定しても、全然中央寄せにならない。
それはそのはずで、.rightの高さ見てみると要素分の高さしか無い。(float指定してるからね!)
中央寄せもなにも上下に余白が無いから、寄るはずも無い。
.rightに高さを指定すればちゃんと中央寄せになるんだけど、可変だから高さを指定したくない。
じゃあfloatで横並びにした要素の高さを親要素の高さに揃えるにはどうしたらいいんだー!
とぜんぜん違う方向に突っ走ってしまい、ドツボにハマっていました。
結論
そもそもこの要件に対してfloat使うからおかしくなる。
display: table-cell
にした要素はそもそもfloat使わなくても横並びになるので、シンプルにこれだけ指定すればよかっただけ。
.wrapper div { display: table-cell; vertical-align: middle; }
凡ミスすぎてどうもすみません。