文字っぽいの。

文字を書いています。写真も混ざります。

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

で元に戻ります。

インデント設定を変える

これは参加しているプロジェクトによりますが、 GitHubSwift Style Guideに追従する場合、インデントはHard Tabになります。

XcodeのPreferences -> Text EditingのIndentationタブで、下記画像のように設定しましょう。

f:id:FromAtom:20160223155319p:plain

行末のスペースを削除 & 空白のみの行から空白を削除

XcodeのPreferences -> Text EditingのEditingタブで、Automatically trim trailing whitespaceIncluding whitespace-only linesにチェックを入れます。

f:id:FromAtom:20160223155500p:plain

爆速で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...の部分が複雑じゃない場合は便利だと思ってる感じです。

追記

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で実行するとこうなる

f:id:FromAtom:20151216150651p:plain

まぁそりゃそうだって感じなんですが、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()

で、これを実行すると

f:id:FromAtom:20151216150750p:plain

ちゃんと黒が返ってくる。それじゃあ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:を作りました。実行してみると

f:id:FromAtom:20151216150916p:plain

黒が返ってきますね。じゃあこの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.で呼んであげれば良いです。

f:id:FromAtom:20151216151041p:plain

ちゃんと赤が返ってきてますね。

ちなみに

f:id:FromAtom:20151216151159p:plain

enumじゃなくても使えたわ。

追記

return blackColor()でいけました。

「師弟登壇2015」でpixivの新卒研修について話してきました。

GMOペパボさんが主催、クックパッドさんに会場提供していただいた『師弟登壇2015』に師弟として登壇してきました。

pepabo.connpass.com

pixivの新卒研修はざっくりと、

  • 業務知識・スキルを学ぶ:7日
  • ビジネスマナーを学ぶ:2日
  • 会社の理念を学ぶ:3日
  • 会社の歴史を知る:1日
  • プログラミングを学ぶ:7日

という感じの内容になっています。発表では@bash0C7さんが企業説明や新卒研修・新卒採用についての概要を説明し、私がプログラミング研修について説明をしました。詳しい内容についてはスライドを見ていただくと分かるかと思います。

発表のメインは、新卒研修の1セクションであるプログラミング研修についてで、

  • 新卒(エンジニア)が新卒(総合職)にプログラミングを教えている
  • 7日間で画像投稿掲示板を作ってもらう
  • 目的はエンジニアと『きもちよく』仕事ができるようになること

といったことを話しました。発表中にもお話したのですが、プログラミング研修は師匠(新卒技術職)サイドに全てが移譲されていて、どんな研修にするか、スケジュールはどうするかなども全て新卒で考えて決めました。

課題の内容や進め方については、去年の例を先輩から聞いて、そこから今年向けにアレンジして行いました。去年の例は書籍にもなっていて、金子本と呼ばれています。総合職にプログラミングを教えたい場合は、この本を買えばいいと思います。(宣伝しても印税は金子氏にしか入らない)

研修の内容や最終的な課題を決める前に、研修の目的を決める必要がありました。この目的が曖昧だと、講義の内容やメンタリングにブレが生じて、学びが曖昧な研修になります。そして、師匠陣で話し合いを行った結果「エンジニアと『きもちよく』仕事ができるようになる」という目的でプログラミング研修を設計していくことになりました。

昨今、エンジニアにとって働きやすい環境・制度がとりあげられる事が増えてきました。しかし、その環境・制度のなかで、非エンジニアの人は楽しく働けているのか疑問でした。そういった疑問を持っていたので、このような目的を提案しました。会社の制度を変えるのは、時間も労力もかかります。なので、まずは新卒間でエンジニアと非エンジニアの壁をできるだけ低くしたいと考えました。

結果として、デザイナさんから「Atom Editorでこういう検索ってどうやるん?」とか、企画の人から「(悪用ではない)スクレイピング勉強したいんじゃー。」という話が出てきて、ちょっとは壁が低くなったのかなと感じております。

f:id:FromAtom:20151206145041j:plain

他にはガイアックスさん、カヤックさん、クックパッドさん、mixiさん、はてなさん、GMOペパボさんが登壇していました。各社とも価値観・文化・世界・規模が違うため、「あー、弊社もそのうちそういうステップになるのかー。」と思いながら聞けて大変おもしろかったです。発表内容については、各社からスライドが公開されてくると思うので省きます。ざっくり感想を書くと、

  • 10万円欲しい
  • テスト駆動学習がゲームみたいで楽しそう
  • 即戦力ではないが"なんか持ってる"人材を育てていく研修を作るの大変そう
  • OJTをどのように回していくと効率的か
  • 研修でチーム作業を失敗して欲しいっての良い
  • 研修をして終わりではなくその後のサポートが大事ですね
  • 採用の段階から研修は始まっているというか、採用で5割研修終わってるのわかる

などなど、色々考えさせられました。

懇親会

様子です。寿司がなんか高給で、普段食べている銀のさら最安桶とは違う匂いを感じました。懇親会はクックパッドスポンサーしてくれて最高の企業という感じです!ありがとうございます!

f:id:FromAtom:20151206172044j:plain

ビールを飲みながら、

  • 人事とCTOと研修担当がしっかり話し合わないと破滅する
  • 人事オンリーやCTOオンリーでやると暴走して破滅する
  • 採用サイドと研修サイドで思想が異なると破滅する
  • ディレクターや企画職の研修をどうするとよいのか
  • 新卒各位、最近仕事どうすか?

という話をぼんやりしました。やはり、新卒研修をする側・受ける側のつらみは色々あって、なんとかしてこれを”おもしろく”解消しようと各社頑張っているという感じです。まぁ、つまらない研修なら、金の力でいくらでもできますからね。

最後に

今回の発表はYAPC2015のトークに応募していました。

yapcasia.org

結果として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
}

たったこれだけなんだけど全然分からなくて、最強のアルバイト氏に相談したら見つかった。さすが最強である。