髪も切れるiOSエンジニアのブログ

元美容師エンジニアの成長と奮闘の記録

ビルド環境切り替え Cococapodsを含めて環境別スキーム追加

担当案件のフルリファクタリングをしているのだが、ビルド環境を切り替えるためにいちいちソースコードコメントアウトを書き換えて行なっているヒューマンエラー紙一重の現状を改善すべく、環境別にスキームを追加することとなった時の話。スキームの追加は簡単だしそれぞれのスキーム設定の追加も難なくできたのだが、Cocoapodsでライブラリをインポートしていたためにつまづいた。同じような経験をした人は多いのではないだろうか。
スキーム追加の参考記事はたくさんあるのだが、Cocoapodsへの対処法の記事は存在しなかったので備忘録を兼ねて。

環境

Xcode 8.3.2
Cocoapods 1.1.1

概要

  • スキームの追加
  • Build Configurationの追加
  • Preprocessor Macrosの追加
  • Other Swift Flagsの設定
  • Cocoapodsの再インポート

スキームの追加

前提として既にCocoapodsによって何らかのライブラリをインポートしているプロジェクトを想定して進める

ビルドターゲットを切り替えるところからManage Schemesを選択
f:id:Tansok:20170615013048p:plain


自分のプロジェクトを選択した状態で、Duplicateを選択
f:id:Tansok:20170615013645p:plain

任意のスキーム名を設定
f:id:Tansok:20170615013852p:plain

これでビルドターゲット欄に自分が入力した名前のスキームが追加される

Build Configurationの追加

Project → Info → Configurationsと選択し、もともと用意されているDEBUGを選択する
f:id:Tansok:20170615014429p:plain

「+」ボタンを押してDuplicate "Debug" Configurationを選択
f:id:Tansok:20170615014703p:plain

コピーが作られるので任意の名前を設定する
f:id:Tansok:20170615014839p:plain

ビルドターゲット選択エリアからEdit scheme...を選択
f:id:Tansok:20170615015025p:plain

はじめに作ったスキームであることを確認し、Build Configurationをさっき作ったものを選択
f:id:Tansok:20170615015331p:plain

Preprocessor Macrosの追加

Targets → Build Settings → Preprocessor Macrosの自分でさっき追加した項目を選択
f:id:Tansok:20170615015907p:plain

$(inherited)を削除し、[任意の名前]=1を入力します。
f:id:Tansok:20170615020341p:plain

Other Swift Flagsの設定

Targets > Build Settings > Other Swift Flagsと選択
f:id:Tansok:20170615020628p:plain

Other Swift Flagsを展開して下の画像のように追加
f:id:Tansok:20170615021016p:plain


これでスキームの追加と各種設定は終了。
一応動作確認の例としては下記

#if DEVELOP
    print("Develop環境")
#else
    print("他の環境")
#endif

しかしこれだけではだめ。はじめに言ったように
既存のライブラリやフレームワークが読み込まれていないことになってる
f:id:Tansok:20170615021724p:plain

Cocoapodsの再インポート

ここからが本題

一旦Podfile内のpodsの文「pod 'Alamofire'」とかの全てコピーをとっとく
そして
Pods関連のファイルを全て削除。さあ、勇気を振り絞って!
f:id:Tansok:20170615022057p:plain

そして

$pod init

$vim Podfile

コピーとっておいたpodsの文を貼り付けて保存

$pod install

ここまでやったら改めて動作確認
f:id:Tansok:20170615023010p:plain

拍手!

まとめ

きっと正攻法ではないのはわかっている。ライブラリのバージョン指定をしていなければ、予期せぬバージョンアップが実行されてしまうしね。
でも自分の環境では今でも健康に動いているので、一つの得策として役に立てればと思う。

ど素人がSES事業に携わり一年過ごして培ったもの

Manhattan Code Inc. もお陰様で本日1周年を迎えることができました。
私は創設の直前にこの会社に入社したので、私にとっても転職を果たしてから1周年ということになります。
この一年間をSESの傭兵として過ごしてきた中で学び感じてきた、SESならではの心構えを綴りたいと思います。
もし同じ立場のSES新人の助けになれば何より。

  • 味方をできる限り増やす
  • 「できる」と「できない」は紙一重
  • SESエンジニアの付加価値

味方をできる限り増やす

弊社マンハッタンコードの方針としては入社から半年は先輩エンジニアと一緒に現場に出る。
半年後問題なしと判断されたら一人で行く現場を探す。
私の場合は若干の手違いもあり三ヶ月で一人で現場に出ることになった。
不安が7割の状態で、「当たって砕けろ」な覚悟を持つことが精一杯だったかもしれない。
実際に一人で現場に出て感じたことはまず「誰にどう質問したらいいのか?」「聞いたらちゃんと答えてくれるのか?」
他力な考えかもしれないが、正直150万ダウンロード越えをしている大手のiOSアプリを単独で開発しきる自信は当時はなかった。
そこでまず「質問しやすい人を増やそう」と考えた。
アサイン初日は環境構築をしながら現場のプロパーさん達がランチに離席するタイミングにアンテナを張った。
今!と感じた時に「ランチですか?ご一緒してもいいですか?」と声をかける。初日に頑張ったのはそれぐらいだ。
ウェルカムランチの風習がある現場に入った人は儲けもの。
自分から声をかけるのは初日だけ、後は毎日ランチに誘ってくれるようになる。
そんな環境が整ったら後はランチの時に自分の話と最近のITニュースの話をふっかける。
自分の場合は長年の美容師を経ての転職というネタもあったので、「今度切りましょうか?」なんて冗談を交えながら。
AppleWWDCまとめサイトとかからネタは常に拾ってきていた。
そんなことを続けていれば自然と「この人は勉強熱心」とか「経験が短いながらも努力家」なんていう印象で見てくれるようになっていた。
弊社には「まずできないエンジニアを目指せ」という教えがある。まさにこのことだ。できないエンジニアほど味方が多い。
普段実装に行き詰まったとしても、もう質問しやすい。「ホントこんな質問するの恥ずかしいんですけど〜」とか「ど忘れしちゃったんで教えて欲しいんですけど〜」とか枕詞で濁しながら。
いやらしい考え方かもしれないが、結果として自分一人で作りあげた納品物とチームに助けてもらいながら作りあげた納品物
納品日にマネージャーから言われる言葉はどちらも「ありがとう。お疲れ様でした。」
事実分からないことが多いなりにも期限が過ぎてしまったなんてことは一度もない。
SESで現場に出る以上、最低限の責任は果たしたい。故に「味方をできる限り増やす」ことは大きな力になる。
その中で私は知識を蓄積していき単独で開発する力をつけることができたと今でも思っている。

「できる」と「できない」は紙一重

よくプロジェクトマネージャーから聞かれることは「これってできますか?」だ。
この受け答えで私が意識していたことは「やったことがないので一旦調査してもいいですか?」だ。
当然当初の自分では「できません」が本音だ。
ただ、「できない」と簡単に答えられてしまったマネージャーの気持ちとしては「iOSエンジニアなんだからなんとかしろよ」になるのが自然だ。
マネージャーとしては実現可能性が閉ざされてしまい、自分としても成長の機会を奪う最も不利益な答えだ。
この「できる」と「できない」は紙一重の状態だとこの一年で実感した。
たまたまTwitterログインを実装したことがある人からすれば、Twitterログイン機能の実装が「できる」だが
たまたまTwitterログインを実装したことがない人からすれば、Twitterログイン機能の実装が「できない」のではなく、「やったことがない」だけで実装手順の調査が必要になる。それだけだ。
「できない」と思っていて15分調査をして15分手を動かした結果、30分後には「できる」と答えることができる自分に変わる。
本当に紙一重だ。
エンジニア歴1年の自分ができてエンジニア歴10年弱の弊社社長ができないことだってあるはずだ。
それはたまたま自分が経験した実装であり、たまたま社長が経験しなかった実装である、ただそれだけのことだ。
この経験から今ではやったことがない実装を要求されたとしてもさほど怖くはない。

SESエンジニアの付加価値

半年が過ぎたあたりでの出来事だ。自分よりも遥かに熟練者I氏がアサインした。
I氏と仲良くなり、もらっている単価を教えてもらった。当然自分よりも遥かに高い。
でもそこで気づいた。もらっている額に差はあるが、実際の仕事内容、機能要件のレベルはそんなに変わらない。
ではなぜI氏の方が遥かに単価が高いのか?I氏を観察することにした。
そこからわかったことは、
機能要件に対しての懸念と代案や打開策を提示していること。さらに打開策のモックも用意して。そのうち客先とのミーティングにも呼ばれるようになっていた。
これが自分にはなくI氏にあるSESエンジニアとしての付加価値だと気づいた。
要求された機能を実装するだけなら自分でもできるようになってはいたが、そんなエンジニアは全国に山ほどいる。
じゃあそんなエンジニア達よりも稼げるエンジニアになるには付加価値が必要だ。
エンジニアリングをするのはお仕事として当然だが、SESの傭兵部隊としてはビジネスをしなければならない。
よく弊社社長が「自分が携わる案件のアプリで常にベストアプリ賞を狙っている」と言うが、これを本気で考えた時に
機能要件を満たすことだけでは足りない。
アプリを企画する側の人間よりもアプリエンジニアの方がアプリのことを知っている。
提示される要件が世の中のニーズからずれていることだって多々ある。そこでSESエンジニアがどう行動するべきか。
懸念点を挙げるだけでは弱い。
代案を出す、もう一息。
実際に作って、当初の案と代案を並べて見せてあげる。
ここまでやって初めて「あなたにお願いしてよかった」なんて言葉が返ってくるのではないだろうか。

まとめ

そんな経験を経て、教訓を得て、
今は一案件のアプリのマネジメントをさせてもらえるようにもなり、客先との仕様決めや設計などの場にも携わることができている。
あくまで持論であり、「そんなの当たり前だ」とか「間違っている」と
十人十色様々な意見があるかもしれない。
でも間違いなく自分の支えの一つになっている経験である。

Git-hub、Sourcetree、Xcodeでバージョン管理

最近弊社マンハッタンコードに新入社員が入りまして、後輩と呼べる存在ができました。
演習課題としてSwiftのトレーニングをしてもらってるのですが、
そのソースをレビューするためにGit-hubを使い
ついでにバージョン管理の導入部分を覚えてしまおうという作戦です。
今回はローカルとリモートにリポジトリを作成する手順をおさらいします。

使用ツール

Git-hub
Source tree 2.3.1
Xcode 8.2.1

導入手順

リモートリポジトリ作成

Git-hubログイン後のトップページにて
f:id:Tansok:20170116011231p:plain
「New Repository」を選択
f:id:Tansok:20170116012220p:plain
リポジトリ名を入力
②Publicを選択
③Create Repositoryを押下

リモートリポジトリをクローンしてローカルリポジトリを作成する

続いてローカルリポジトリをSource treeを使って作成します。
まずはローカルリポジトリ用のディレクトリを作ります。
f:id:Tansok:20170116013337p:plain
ファインダーから新規でフォルダを作成
f:id:Tansok:20170116013526p:plain
次はSource treeの作業です。
「+新規リポジトリ」を押下 → 「URLからクローン」を選択
f:id:Tansok:20170116013841p:plain
このような画面になります。
ここで一旦Git-hubに戻ります。
f:id:Tansok:20170116012653p:plain
リモートリポジトリのパスをコピーします。
f:id:Tansok:20170116015055p:plain
①「ソースURL」にコピーしたリモートリポジトリのパスをペースト
②「保存先のパス」入力フォームを選択(パスが自動入力される)
③「...」を選択してフォルダを開く
f:id:Tansok:20170116014628p:plain
①さっき作ったローカルのディレクトリを選択
②「開く」を押下
f:id:Tansok:20170116014834p:plain
クローンを押下
f:id:Tansok:20170116015238p:plain
自動でSource treeのバージョン管理画面が立ち上がります。
これでローカルリポジトリの作成が完了

xcodeから新規プロジェクトを作成

新規プロジェクト作成方法は割愛します。
新規プロジェクトの保存先選択時に
f:id:Tansok:20170116015827p:plain
①先ほどローカルリポジトリを作成した同じディレクトリを選択する
②Createを押下
f:id:Tansok:20170116020222p:plain
プロジェクトが作成され、
Source treeに差分が反映されていれば完了です。

まとめ

自分が業界入りたての時に苦労したのがこの作業でした。
懐かしい。
今後後輩の備忘録として役立てば何より。

おやすみなさい。

実はできない!UISliderのタップ移動

f:id:Tansok:20170114010612p:plain
UISliderはタブをスワイプで移動させるUIパーツですが、
タップでタブを移動させたい場面がやたら多い印象。
参考記事を探してもObj-C版はあるけど、Swiftはなかった(多分だよ)

環境

Xcode 8.2.1
Swift 3.0

実装

たったの2stepで実現可能

  • UISliderの独自カスタムクラスを実装
  • UISliderにカスタムクラスをセット

UISliderの独自カスタムクラスを実装

まずは独自クラスでカスタムUISliderを作成します。

import UIKit

class MySlider: UISlider {
    
    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        return true
    }
}

たったこれだけ

UISliderにカスタムクラスをセット

あとはStoryboardからUISliderをセットして、
Custom Classに独自UISliderクラスをセットするだけ
f:id:Tansok:20170114012404p:plain
コードから使いたい時は

var slider: MySlider!

ですね。

おしまい。

Screen Heroでペアプログラミング

2016年ももうおわり。来年からは自社サービス開発も本格的に始動するから
ますます濃い年になるのではないでしょうかい。
そんな我社マンハッタンコードに最近、画面共有でのペア開発ツールが導入されましたのでご紹介。

Screen Hero

screenhero.com
Slackアカウント一つで普段使っているSlackチーム間でのペアプログラミングが可能になる優れもの!

導入手順

まずはブラウザ版Slackチームにサインインします。
f:id:Tansok:20161223202456p:plain
左上のプロフィールの編集等ができるプルダウンを開き
「Apps&integrations」を選択します。

f:id:Tansok:20161223192035p:plain
検索フォームで「screen」と検索すれば「Screenhero」が候補にでてくるので選択します。

f:id:Tansok:20161223192354p:plain
使用ガイド画面に来ました。ここでは一旦「expand」を選択して、出現したテキスト内のリンク「Create your free Screenhero account」を選択します。

f:id:Tansok:20161223192954p:plain
緑のボタン「Try Screenhero with...」を選択します。

f:id:Tansok:20161223193310p:plain
「Download Screenhero」を選択します。
zipファイルがダウンロードされますので展開してScreenheroを起動します。

f:id:Tansok:20161223193718p:plain
すると右上のメニューバーの部分にScreenheroのロゴが追加されます。
ここからいつでも起動可能になります。
起動したらサインインを求められます。

f:id:Tansok:20161223200943p:plain
スクリーン共有したいユーザを選んで、
「Share your screen」を選択します。

f:id:Tansok:20161223201533p:plain
シェアを求められたユーザには上のダイアログが表示されるので
「Accept Share」を選択します。
これでスクリーンの共有が可能になります。
当然ペアプログラミングツールなので、相手の画面に書き込みことが可能です!
リモートの作業が多くなるプロジェクトにはもってこいのツールの一つになること間違えなしですね!

Screenhero作業中にお腹が痛くなってトイレに中座すると
意地悪な先輩にエロサイトをたくさん開かれる被害にあいますのでご注意ください。

自作家計簿アプリ製作の軌跡④ 〜UIパーツにシャドウを〜

これからアプリ内のUIパーツにシャドウを設定していくことが多くなりそうだ。
一発メソッド呼び出しでシャドウをつけたい!かつ細かい設定ができるようにしたいと!
ということで拡張してシャドウ用メソッドを作りました。

環境

xcode 8.1
swift 3.0

実装

UIViewクラスを拡張します。

import UIKit

// UIViewを拡張して
extension UIView {
    /// UIViewを継承するUIパーツにシャドウを設定するメソッド
    /// - parameter opacity: 影の濃さ
    /// - parameter radius: 影のぼかし具合
    /// - parameter x: 水平方向の影の出し具合
    /// - parameter y: 垂直方向の影の出し具合
    ///
    func setShadow(opacity: CGFloat, radius: CGFloat, x: CGFloat, y: CGFloat) {
        self.layer.shadowOpacity = opacity
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowRadius = radius
        self.layer.shadowOffset = CGSize(width: x, height: y)
    }

呼び出しは

setLabel.setShadow(opacity:1.0 radius: 2.0, x: 0, y: 3.0)

UIViewを拡張してるから
UIViewを継承するUIパーツならなんでも使える!
もっと便利な拡張があったら教えてください!

つづく

自作家計簿アプリ製作の軌跡③ 〜NavigationControllerの実装〜

今回はNavigationControllerの実装です。
アプリの仕様的に階層の深い作りにする気はないので
NavigationBarをStoryBoardで取り入れればいいかとも思いましたが、
将来的なバージョンアップで画面数の増加も考えてNavigationControllerを取り入れました。
でも、実装している中で大きな誤解に気づいたので記事にします。

環境

xcode 8.1
swift 3

実装

前提として、自分の家計簿アプリはトップ画面にTabBarを置いた作りです。
なんとなくNavigationControllerってStoryBoardで言うところの
遷移の一番初めの親のViewに置くイメージが強かったので
f:id:Tansok:20161126235620p:plain
迷わずこうした訳です。
NavigationControllerのrootViewControllerにTabBarControllerを設定してます。
実機でデバッグしてみても全画面にNavigationBarが設置されており
「よしっ」なんて思いましたが、落とし穴がありました。
それぞれのViewControllerの「title」を設定してみてもNavigationBarに
表示されません!なんでだ?!
そこで素直に先人の知恵を求めてみました。
あったあった。
TabBarControllerとNavigationControllerを同時に使う(Storyboard) - Qiita
tabBarControllerとUINavigationControllerを同時に使いたい! - Takahiro Octopress Blog
要するに、階層構造にしたい親のViewに設定しなければいけないってこと。
NavigationControllerのrootViewController以下の遷移は「push」か「show」結ばれていなければならないってこと。
自分のアプリのトップ画面はTabBarControllerで、その子は「viewControllers」で3画面持っている状態です。
なんか理科の電流の授業を思い出しましたけど、並列繋ぎではNavigationControllerは機能しないんですね。
f:id:Tansok:20161127001336p:plain
結論はこう。
TabBarから分岐した遷移の配下からNavigationControllerを置きましょう。

おまけ

ちなみにNavigationControllerが複数になったとしても
AppDelegateクラスのdidFinishLaunchingWithOptions内で

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        // ナビゲーションバーのカラー設定
        UINavigationBar.appearance().barTintColor = UIColor.orange()
        // ナビゲーションバーのフォント設定(フォント名、サイズ)
        let attributes =
            [NSForegroundColorAttributeName:UIColor.white,
             NSFontAttributeName: UIFont(name:"Futura", size:25)!]
        UINavigationBar.appearance().titleTextAttributes = attributes
        // タブバーのカラー設定
        UITabBar.appearance().barTintColor = UIColor.orange()
        
        return true
    }

appearance()メソッドを使えば全画面NavigationBarを一括で変更、統一できます。

つづく