毎回忘れてTwilog見に行ってるので書いておく。
let array: [Int] = [1, 2, 3, 4, 5] let lastIndex = array.endIndex.predecessor() print(lastIndex) // => 4
@FromAtom あ,それで合ってます.添字に使いたかったら `array.endIndex.predecessor()` とするのがオシャレです
— やしがに (@yashigani) 2016年3月25日
毎回忘れてTwilog見に行ってるので書いておく。
let array: [Int] = [1, 2, 3, 4, 5] let lastIndex = array.endIndex.predecessor() print(lastIndex) // => 4
@FromAtom あ,それで合ってます.添字に使いたかったら `array.endIndex.predecessor()` とするのがオシャレです
— やしがに (@yashigani) 2016年3月25日
題名の通り。git commit
にHookして、変更がある*.swift
ファイルにのみLintをかける。Lintでコケたらcommitされなくて便利。
#!/usr/bin/env ruby require 'yaml' LINT_CONFIG_FILE_NAME = '.swiftlint.yml' updated_swiftfiles = `git diff --cached --name-only --diff-filter=AM -- '*.swift'`.split("\n") exit if updated_swiftfiles.empty? lint_config = YAML.load_file(LINT_CONFIG_FILE_NAME) default_included = lint_config['included'] lint_config['included'] = updated_swiftfiles open(LINT_CONFIG_FILE_NAME, 'w') do |file| YAML.dump(lint_config, file) end `swiftlint lint` lint_config['included'] = default_included open(LINT_CONFIG_FILE_NAME, 'w') do |file| YAML.dump(lint_config, file) end
こういう内容を "your-repo/.git/hooks/pre-commit" に書いておくだけ。
不適切に使われてる(型を消すとか)場合には絶対に直させる。型を消したい場合は protocol
+ typealias
とかgenerics
でなんとかできる場合が多い。というか AnyObject
を使ってるコードでは、型を消す必要がない場合が多い。
let item = items[index]
とか。基本的にはindex
など使わずにアクセスするのが一番なので、書き直せないか確認する。
書き直せない場合はロジック自体の設計を変えられないか、もしくははみ出ない処理がちゃんと書かれているかを確認している。
let width = optionalView!.frame.width let dic = unknownAnyObject as! [String : String] someFuction(optionalData!)
クラッシュ原因ほとんどはこれ。安易にForce Unwrapすべきではない。
if let width = optionalView?.frame.width { // この中で `witdh` を使う } if let dic = unknownAnyObject as? [String : String] { // この中で `dic` を使う } if let data = optionalData { someFunction(data) }
ちなみに、StoryBoard系とかCell系とかの呼び出しには使っても良い。
let storyboard = UIStoryboard(name: "WelcomePage", bundle: nil) let viewController = storyboard.instantiateInitialViewController() as! WelcomePageViewController
なぜなら、これらが無かった時にエラーハンドリングできない。できても画面が真っ白になるとかそういう感じなので、デバッグ中やQA中にクラッシュしてもらって素早く直した方が良い。
self
呼んでるのに weak
or unowned
になってないlet queue = dispatch_queue_create("com.example.task", DISPATCH_QUEUE_SERIAL) dispatch_async(queue) { self.someFunction(self.someData) }
非同期処理中では self
が先に消えてることがあり、アクセスするとクラッシュする場合がある。
let queue = dispatch_queue_create("com.example.task", DISPATCH_QUEUE_SERIAL) dispatch_async(queue) { [weak self] self?.someFunction(self?.someData) }
weak
にしておくと、block内のself
がOptionalとして扱われるので、安心して使える。
これは誤りです。非同期処理中のself
は強参照で確保されているため、self
が先に消えることはないため、weak
やunowned
にする必要はありません。ブコメ等でご指摘いただいた皆様、ありがとうございました。
delegate
が weak
じゃないprotocol SomeDelegate: class { func updateItem() } class SomeClass { var delegate: SomeDelegate? }
とか宣言されてる。ようこそ循環参照の村へという感じになる。 delegate
には大体親の ViewController
から self
を渡すので、これを weak
にしておかないと SomeClass
のインスタンスは永遠に開放されない。「なんで deinit()
呼ばれないんだろ?」と思ったらだいたいこれが原因。
protocol SomeDelegate: class { func updateItem() } class SomeClass { weak var delegate: SomeDelegate? }
ちゃんとweak
にしようなっ!
!=
でしてるif optionalValue != nil { awesomeMethod(optionalValue!) }
Obj-Cっぽい。Swiftでこういう書き方をしなければいけない場面はほぼない。
if let value = optionalValue { awesomeMethod(value) }
と書ける。もし、nil
かどうかだけ見たくてblock内では利用しない場合は
if let _ = optionalValue { // do something }
と書くのが良い。
if someFlag { // 10行ぐらいの処理 } else { // 1行の処理 }
10行の処理
って書いてるけど、だんだん10行とかでは済まない長さになり、ネストが深くなり、可読性が下がる。可読性が下がるとエンバグしやすくなる。エンバグすると人が死ぬ。
guard someFlag else { // 1行の処理 return } // 10行の処理
と素早くreturn
してのが良い。
guard
や if
で return
してるfor item in items { guard item.someFlag else { return } }
guard
慣れしてくるとうっかりミスる奴。return
ではなくてbreak
とか continue
じゃないとダメな場合があるので、気をつけて見ている。
??
で書けるところを if
で分岐しているlet x: CGFloat let y: CGFloat if let view = optionalView { x = view.frame.x y = view.frame.y } else { x = 0 y = 0 }
大体の場合においてコードが長くなって可読性が下がる。optionalValue
が nil
だった場合にエラーハンドリングしたい場合はこの書き方で良いが、値が欲しくてデフォルト値も決まっている場合は
let x: CGFloat = optionalView?.frame.x ?? 0 let y: CGFloat = optionalView?.frame.y ?? 0
と書くと良い。
if view.frame.width > 540 { width = 540 } else { width = view.frame.width }
view
のサイズが540より大きかったら540にして、そうじゃないならview
のサイズを使うというやつ。こういう処理をする時はだいたい高さや縦横比なんかの計算が混ざるので、上記みたいにシンプルに終わらず if
のネストが始まってつらい。
let width = min(540, view.frame.width)
こうするとシュッと終わる。
iOS開発をしていると、*.xcworkspace
や*.xcodeproj
をよく開きます。Xcodeはよく落ちるし調子が悪くなると再起動しないといけないので、1日に何度も開いたりします。
$ cd ios-project $ open . # おもむろにクリック
$ cd ios-project $ ls # ディレクトリ内の様子みる $ open awesome-app.xcworkspace
function open-xcode-project() { open *.xcworkspace || open *.xcodeproj || echo 'fatal: Not a Xcode repository' } alias xc='open-xcode-project'
これを設定しておけば
$ cd ios-project
$ xc
だけで開く
ディレクトリに移動するのもxc
を打つのも面倒なので、pecoと組み合わせます。
function open-xcode-project() { open *.xcworkspace || open *.xcodeproj || echo 'fatal: Not a Xcode repository' } function peco-cdr-and-open-xcode () { local selected_dir=$(cdr -l | awk '{ print $2 }' | peco) if [ -n "$selected_dir" ]; then BUFFER="cd ${selected_dir} && open-xcode-project" zle accept-line fi zle clear-screen } zle -N peco-cdr-and-open-xcode bindkey "^x^o" peco-cdr-and-open-xcode
こうしておくと Ctrl-x Ctrl-o
と押すだけでpecoで最近開いたディレクトリを検索でき、ディレクトリを選ぶと、その中のXcodeプロジェクトが開かれます。
オペラシティで開催されている、『ライアン・マッギンレー BODY LOUD !|東京オペラシティアートギャラリー』を観に行ってきた。
写真撮影可能だったので、気に入ったのを撮った。
GW後の土日ということもあり、あまり人もいなくて良かった。特にこのインスタレーションがすごかった。
ヌードというよりも、動物としてのヒトを撮影した感じで良さがあった。こういう生き物がいるんだなぁという感じ。ちょうど、『家畜人ヤプー』を読んでいる所だったので、「人間よりも高位の存在がいたら。」とか考えながら見てた。
新宿から1駅なので、暇があったら行ってみると良いと思います。7月10日までとのこと。
そういえば、ふともも写真の世界展に行きそびれたので、僕はもうダメです。
バグを見つけて教えてくれるのは嬉しいしありがたい。ユーザの体験損失や脆弱性を防ぐことができて良い。これは何にも勝る絶対的な真理である。
しかし、なにか変な挙動を見つけた時に脊髄反射的に「これバグじゃね?」と言うのは良くない。この発言はただの いちユーザの発言 であり、サービスやアプリを提供する側の人間としては、恥ずべき発言だと思う。
そもそも、その挙動の「バグか、仕様か」を判断するのは開発者であって、ユーザではない。「これバグじゃね?」は思考停止した愚かな発言であり、
という背景がある(かもしれない)挙動を十把一絡げに「バグじゃね?」と言うのは良くない。
「これバグじゃね?」と言われた時の感覚は「なんかお前臭くね?」と言われたのと同じ感じがある。「えっ、マジで?なんか変なの食べたっけ?にんにく?ニンニク食べたっけ?昨日風呂入ったよな?入ったよ。入浴剤も入れて入ったね。もしかして加齢臭?これが噂の加齢臭なのか?もしかしてワキガ?ワキガなのか?手術とか受けたほうが良いのかな?つら。」ぐらいに脳みそが回転してバグに構える。それだけエンジニアはバグに対して敏感に生きている。
もし「バグじゃね?」と言われた挙動がバグだった場合は「バグだわ。死にたい。」という気持ちになるし、バグじゃなくて意図した挙動だった場合は「なんやお前殺すぞ。」という気持ちになる。上記の例では「あぁ、お前の匂いじゃないわ。なんかエアコンが臭いわ。お前臭くねーわwwがははww」とか言われた感じですね。殺してやりたくなりますよ。
アプリを触ってたらクラッシュしたり、ふぁぼったのに反映されてなかったり、500エラーが出てたり。明らかなバグなら「バグっぽいです。」と教えてあげればよいです。
また、それを伝える際に どういう手順で動かすとバグるか を一緒に伝えてあげると大変助かると思います。「この画面でボタン押したらバグったけど、今は大丈夫。」って言われても「何もしてないのにパソコンが壊れた。」と言われるのと同じくらい「どうしろってんだ」感があります。
「この画面で、こうしたらAになったんですが。なんか私的には、Bになる気がするんですが、なにか理由がありますか?」とか聞いてもらえると、意匠がある場合はそれを教えることができますし、ただのバグなら「殺してくれ。」って良いながらIssueを立てます。
最初から殴る気満々でコミュニケーションを始めるのはやめよう。