立替金の精算申請を忘れてはならぬ。
XcodeでiOS開発を始める前にしておくと便利な準備
デバイス接続時にPhoto.app
を起動しないようにする
バグ検証時に検証機ではなく、個人のiPhoneを接続することがたまにありますが、便利なことにPhoto.app
が起動して、他人の写真が見放題です。「あぁ!すいませんすいません!」と焦って⌘Q
を連打する前に、そもそも起動しないように設定しておきましょう。
defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool YES
元に戻したい場合は
defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool NO
で元に戻ります。
インデント設定を変える
これは参加しているプロジェクトによりますが、 GitHubのSwift Style Guideに追従する場合、インデントはHard Tabになります。
XcodeのPreferences -> Text EditingのIndentationタブで、下記画像のように設定しましょう。
行末のスペースを削除 & 空白のみの行から空白を削除
XcodeのPreferences -> Text EditingのEditingタブで、Automatically trim trailing whitespace
とIncluding whitespace-only lines
にチェックを入れます。
爆速でiOSアプリのカラー設定をするための`extension`と`enum`
アプリを爆速で作りたい時に、最も時間を浪費するのが色の指定です。StoryBoard上で設定してしまうと、あとから調整をしたい場合、複数ある画面全てを渡り歩いて、丁寧な手作業で色をポチポチしていく必要があります。また、UIColorを使う場合でも、設定があちこちに分散してしまったり、RGB[0 - 255]での設定が難しくてつらい気持ちになったりします。
なので、Webで一般的な16進数表記でUIColorを生成できるようにして、生成したい色のセットをenum
で管理するようにしました。
色を指定する際は、16進数で書けたほうが便利なのですが、UIColorは16進数表記でイニシャライズさせてくれません。ので、拡張します。
// 16進数表記からUIColorに変換する拡張 extension UIColor { convenience init?(hexString: String, alpha: CGFloat = 1.0) { let validatedHexColorCode = hexString.stringByReplacingOccurrencesOfString("#", withString: "") let scanner = NSScanner(string: validatedHexColorCode) var colorCode: UInt32 = 0 guard scanner.scanHexInt(&colorCode) else { print("ERROR: 色変換に失敗しました。") return nil } let R = CGFloat((colorCode & 0xFF0000) >> 16) / 255.0 let G = CGFloat((colorCode & 0x00FF00) >> 8) / 255.0 let B = CGFloat(colorCode & 0x0000FF) / 255.0 self.init(red: R, green: G, blue: B, alpha: alpha) } }
これで UIColor(hexString: "#ffffff")
とインスタンスを生成することが出来ます。ちなみに、ここの処理は最初は関数になっていたのですが、最強のアルバイト氏が書きなおしてくれました。convenience
ってこうやって使うんかって知った。さすが最強。
次にいくつかの16進数カラーコードを、enum
で管理します。
// 色設定 enum ColorSet: String { case Background = "F9F5EF" case Primary = "2E97D8" case White = "FFFFFF" case Gray = "D0CAC1" var UIColor: UIKit.UIColor { return UIKit.UIColor(hexString: self.rawValue)! } var CGColor: UIKit.CGColor { return self.UIColor.CGColor } }
こんな感じで定義しておけばColorSet.Primary.UIColor
と呼び出すことができて大変便利です。また、急に「寒色系じゃなくて暖色系の色合いがいい」と言われた場合でも、このColorSet
をいじるだけでアプリ全体の色を調整する事が可能になっています。またこれにより、Web側やSketch等各種デザインツールで設定されたカラーコードを、簡単に反映する事ができるようになりました。
Swiftの"[weak self]"にアクセスする時に"if let weakSelf = self"とか"self?"を書きたくない人へ
今まで
大体の場合、
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { [weak self] response in guard let weakSelf = self else { return } // do something... weakSelf.tableView.reloadData() }
とか
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { [weak self] response in // do something... self?.tableView.reloadData() }
と書きます。
違う書き方
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { [weak self] response in guard let `self` = self else { return } // do something... self.tableView.reloadData() }
便利!
余談
SlackのSwiftJPチャンネルで色々議論されてて面白い。個人的には、// do something...
の部分が複雑じゃない場合は便利だと思ってる感じです。
追記
バッククオートでselfに代入できるのはおそらくバグだとアップルの人の回答。その上でこの提案が受け入れられたら、普通にselfにguard節で代入できるようになる。 https://t.co/MVT7iEO5Pu https://t.co/MGYfn6YcHB
— kishikawa katsumi (@k_katsumi) 2016, 1月 20
enumオモシロ記法
Swiftで色やフォントを管理するのにはenumを使うのが大変便利ですよね。次の例は流石に雑ですが、だいたいこんな感じで管理してると思います。
import UIKit enum Colors { case black case white func color() -> UIColor { switch self { case black: return UIColor.blackColor() case white: return UIColor.whiteColor() } } } Colors.black.color()
これをPlaygroundで実行するとこうなる
まぁそりゃそうだって感じなんですが、UIColor.blackColor()
と書いている部分を.blackColor()
にする事ができます。
import UIKit enum Colors { case black case white func color() -> UIColor { switch self { case black: return .blackColor() case white: return .whiteColor() } } } Colors.black.color()
で、これを実行すると
ちゃんと黒が返ってくる。それじゃあblackColor:
というメソッドを生やしたらどうなるんでしょうか?
import UIKit enum Colors { case black case white func color() -> UIColor { switch self { case black: return .blackColor() case white: return .whiteColor() } } func blackColor() -> UIColor { return .redColor() } } Colors.black.color()
新しくblackColor:
を作りました。実行してみると
黒が返ってきますね。じゃあこのblackColor:
を実行するにはどうすればよいかというと
import UIKit enum Colors { case black case white func color() -> UIColor { switch self { case black: return self.blackColor() case white: return .whiteColor() } } func blackColor() -> UIColor { return .redColor() } } Colors.black.color()
self.
で呼んであげれば良いです。
ちゃんと赤が返ってきてますね。
ちなみに
enumじゃなくても使えたわ。
追記
@FromAtom selfつけんくても`.`をとればいけるのでは?
— やしがに (@yashigani) 2015, 12月 16
return blackColor()
でいけました。
「師弟登壇2015」でpixivの新卒研修について話してきました。
GMOペパボさんが主催、クックパッドさんに会場提供していただいた『師弟登壇2015』に師弟として登壇してきました。
pixivの新卒研修はざっくりと、
- 業務知識・スキルを学ぶ:7日
- ビジネスマナーを学ぶ:2日
- 会社の理念を学ぶ:3日
- 会社の歴史を知る:1日
- プログラミングを学ぶ:7日
という感じの内容になっています。発表では@bash0C7さんが企業説明や新卒研修・新卒採用についての概要を説明し、私がプログラミング研修について説明をしました。詳しい内容についてはスライドを見ていただくと分かるかと思います。
発表のメインは、新卒研修の1セクションであるプログラミング研修についてで、
- 新卒(エンジニア)が新卒(総合職)にプログラミングを教えている
- 7日間で画像投稿掲示板を作ってもらう
- 目的はエンジニアと『きもちよく』仕事ができるようになること
といったことを話しました。発表中にもお話したのですが、プログラミング研修は師匠(新卒技術職)サイドに全てが移譲されていて、どんな研修にするか、スケジュールはどうするかなども全て新卒で考えて決めました。
課題の内容や進め方については、去年の例を先輩から聞いて、そこから今年向けにアレンジして行いました。去年の例は書籍にもなっていて、金子本と呼ばれています。総合職にプログラミングを教えたい場合は、この本を買えばいいと思います。(宣伝しても印税は金子氏にしか入らない)
pixivエンジニアが教えるプログラミング入門 (星海社新書)
- 作者: 金子達哉
- 出版社/メーカー: 講談社
- 発売日: 2015/03/26
- メディア: 新書
- この商品を含むブログ (1件) を見る
研修の内容や最終的な課題を決める前に、研修の目的を決める必要がありました。この目的が曖昧だと、講義の内容やメンタリングにブレが生じて、学びが曖昧な研修になります。そして、師匠陣で話し合いを行った結果「エンジニアと『きもちよく』仕事ができるようになる」という目的でプログラミング研修を設計していくことになりました。
昨今、エンジニアにとって働きやすい環境・制度がとりあげられる事が増えてきました。しかし、その環境・制度のなかで、非エンジニアの人は楽しく働けているのか疑問でした。そういった疑問を持っていたので、このような目的を提案しました。会社の制度を変えるのは、時間も労力もかかります。なので、まずは新卒間でエンジニアと非エンジニアの壁をできるだけ低くしたいと考えました。
結果として、デザイナさんから「Atom Editorでこういう検索ってどうやるん?」とか、企画の人から「(悪用ではない)スクレイピング勉強したいんじゃー。」という話が出てきて、ちょっとは壁が低くなったのかなと感じております。
他にはガイアックスさん、カヤックさん、クックパッドさん、mixiさん、はてなさん、GMOペパボさんが登壇していました。各社とも価値観・文化・世界・規模が違うため、「あー、弊社もそのうちそういうステップになるのかー。」と思いながら聞けて大変おもしろかったです。発表内容については、各社からスライドが公開されてくると思うので省きます。ざっくり感想を書くと、
- 10万円欲しい
- テスト駆動学習がゲームみたいで楽しそう
- 即戦力ではないが"なんか持ってる"人材を育てていく研修を作るの大変そう
- OJTをどのように回していくと効率的か
- 研修でチーム作業を失敗して欲しいっての良い
- 研修をして終わりではなくその後のサポートが大事ですね
- 採用の段階から研修は始まっているというか、採用で5割研修終わってるのわかる
などなど、色々考えさせられました。
懇親会
様子です。寿司がなんか高給で、普段食べている銀のさら最安桶とは違う匂いを感じました。懇親会はクックパッドスポンサーしてくれて最高の企業という感じです!ありがとうございます!
ビールを飲みながら、
- 人事とCTOと研修担当がしっかり話し合わないと破滅する
- 人事オンリーやCTOオンリーでやると暴走して破滅する
- 採用サイドと研修サイドで思想が異なると破滅する
- ディレクターや企画職の研修をどうするとよいのか
- 新卒各位、最近仕事どうすか?
という話をぼんやりしました。やはり、新卒研修をする側・受ける側のつらみは色々あって、なんとかしてこれを”おもしろく”解消しようと各社頑張っているという感じです。まぁ、つまらない研修なら、金の力でいくらでもできますからね。
最後に
今回の発表はYAPC2015のトークに応募していました。
結果としてYAPCはリジェクトされちゃったのですが、お蔵入りせずに話せて良かったなぁという気持ちでおります。
最後になりますが、運営のGMOペパボさん、会場と寿司提供のクックパッドさん、登壇した各社師弟さん、本当におつかれさまでした!
Swift2.0のprotocol extension試してたら'Segmentetion fault: 11'でてハマった。
書いたコード
protocol Test { var x: CGFloat { get set } var y: CGFloat { get set } func setPoint(point: CGPoint) } extension Test { mutating func setPoint(point: CGPoint) { x = point.x y = point.y } } struct test: Test { var x: CGFloat = 0.0 var y: CGFloat = 0.0 }
出るエラー
ビルドはできないし、Xcodeのシンタックスハイライトも死んで白き灰がちになりてわろし。
0 swift 0x0000000105b9b33b llvm::sys::PrintStackTrace(__sFILE*) + 43 1 swift 0x0000000105b9ba7b SignalHandler(int) + 379 2 libsystem_platform.dylib 0x00007fff81b9752a _sigtramp + 26 3 libsystem_platform.dylib 0x00007fff5bf79768 _sigtramp + 3661505112 4 swift 0x0000000103e64857 swift::SILWitnessVisitor<(anonymous namespace)::SILGenConformance>::visitProtocolDecl(swift::ProtocolDecl*) + 999 5 swift 0x0000000103e62035 swift::Lowering::SILGenModule::getWitnessTable(swift::ProtocolConformance*) + 277 6 swift 0x0000000103eb1890 (anonymous namespace)::SILGenType::emitType() + 1264 7 swift 0x0000000103eb132e swift::Lowering::SILGenModule::visitNominalTypeDecl(swift::NominalTypeDecl*) + 30 8 swift 0x0000000103e39e0b swift::Lowering::SILGenModule::emitSourceFile(swift::SourceFile*, unsigned int) + 779 9 swift 0x0000000103e3a9c0 swift::SILModule::constructSIL(swift::ModuleDecl*, swift::SILOptions&, swift::FileUnit*, llvm::Optional<unsigned int>, bool, bool) + 928 10 swift 0x0000000103e3ad6d swift::performSILGeneration(swift::FileUnit&, swift::SILOptions&, llvm::Optional<unsigned int>, bool) + 109 11 swift 0x0000000103c8eb92 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&) + 11442 12 swift 0x0000000103c8bcd3 frontend_main(llvm::ArrayRef<char const*>, char const*, void*) + 2691 13 swift 0x0000000103c88354 main + 2324 14 libdyld.dylib 0x00007fff844be5ad start + 1 Command failed due to signal: Segmentetion fault: 11
とか出る。
解決法
protocolにちゃんとmutating
をつける。
protocol Test { var x: CGFloat { get set } var y: CGFloat { get set } mutating func setPoint(point: CGPoint) } extension Test { mutating func setPoint(point: CGPoint) { x = point.x y = point.y } } struct test: Test { var x: CGFloat = 0.0 var y: CGFloat = 0.0 }
たったこれだけなんだけど全然分からなくて、最強のアルバイト氏に相談したら見つかった。さすが最強である。