emahiro/b.log

Drastically Repeat Yourself !!!!

プロトコルでのオプショナルなインターフェースを作る。

Protocolの定義

宣言したインターフェースは継承先のクラス、もしくはプロトコル、構造体で、宣言必須。
とはいえ、必要ないインターフェースは継承先で記述省きたいとも思う。
そこでswiftで使えるオプショナルなインターフェースについて調べてみた。

オプショナルなインターフェース

参考 swiftの公式ドキュメント
https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267

You can define optional requirements for protocols, These requirements do not have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the optional modifier as part of the protocol’s definition. Optional requirements are available so that you can write code that interoperates with Objective-C. Both the protocol and the optional requirement must be marked with the @objc attribute. Note that @objc protocols can be adopted only by classes that inherit from Objective-C classes or other @objc classes. They can’t be adopted by structures or enumerations.

オプショナルなインターフェースの定義方法

protocol SomeProtocol{

  @objc optional func someMethod

}

@objc修飾子とoptional修飾子が必須 特に@objc修飾子がないとオプショナルなインターフェースは定義できない。

使い所

オプショナルなインターフェースにすれば、継承先のオブジェクトでインターフェースの宣言は必須でなくなる。
クラス設計に寄っては、継承先のオブジェクトで不必要なインターフェースも存在するので、設計を厳格にコードに落とし込む上でも有用。

ただし、このこちらのブログにあるように、optionalにすることで厳格性が失われたり、@objc 修飾子をつけることで、swiftの良さがなくなることもあるので、導入には議論が必要になりそう。

既存のコードの書き換え時には使えるなと感じつつも

  1. オプショナルを使わずに厳格にインターフェース定義できるプロトコルを設計段階で実装できることの方が大事
  2. メソッドに対して ?! といった明示的なunwrapを使うのがコードとしては美しくないと感じる

とも感じるので、設計の初手から使うことは考えずにいたい。

swift学習ログ「タプル」

swiftのタプルについて

公式リファレンス呼んだ備忘録
php, rubyと経験してきて、swiftを学習し始めてから「tuple」という概念を知ったのでまとめます。

タプルとは?

タプル(tuple)とは、複数のものからなっている組の構成要素数を表している集合数詞である。2つ組、3つ組などのそれぞれを表す英単語が一般化された言葉から派生し、数学や計算機科学などの分野では、通常順序つけられた対象の並びを表すために用いられる (出典: 日立ソリューションズ IT用語辞典)

タプルとは集合数詞ということで、なんかよくわからないものと捉えてましたが、Collectionというより変数に近い扱いをするものだと理解して続けます。

タプルの定義と使い方

参考 : Swift Gideline

// 定義の仕方
let httpStatus404 = (404, "Not Found")

// タプルごと定数定義もでき、アクセスもできる
let (statusCode, statusMessage) = httpStatus404
print(statusCode) // => 404
print(statusMessage) // => Not Found

// ワイルドカードもつかえる
let (statusCode, _) = httpStatus404
print(statusCode) // => 404

// tapleで宣言された変数へのアクセス方法
let firstElement = httpStatus404.0 // 404
let SecondElement = httpStatus404.1 // Not Found

// 要素に名前をつけることもできる
let httpStatus200 = (statusCode: 200, statusMessage: 'OK')
let statusCode = httpStatus200.statusCode // 200
let statusMessage = httpStatus200.statusMessage // OK

使い所

イマイチ最初tupleの使い所がわからなかったのですが、座標とかまさにこの形だなと思ったり、要素でまとめられる場合、配列やディクショナリといったCollectionを使わずに、要素を扱いたい時に使えるかなと言った印象。 積極的に現場で使っていきたい。

読書 Note -「人工知能は人間を超えるか」~ディープラーニングの先にあるもの~

背景

今年は間違いなくAIだったり深層学習だったりがバズワードになり、色んな製品にそういった技術が使われてくる世の中になるだろうと思います。
そんな中、結局「AI」とか「人工知能」とか「深層学習」ってそもそも何?っていうことの背景だったり歴史だったりを知ろうと思って読みました。

書評

  • 深層学習
  • AI

といったバズワードの実態を知るには最適の書籍でした。
エンジニアとして、そもそもそういう技術が何なのか?ということを全く理解していなかったことがわかり、これから自分がどういった姿勢でこれらの技術に対峙していくべきなのかを学ぶことができたと思います。

そもそもAIって?

結局、僕が知りたかった、というか疑問に思っていた箇所はこの一点でした。
何でもかんでも「AI」とか「人工知能」って言う言葉が軽々しく使われていて、一体何が人工知能なのかを理解していなかったのですが、

  • 現時点においても、AI(artificial intelligence)といえるものは存在していないこと。
  • 深層学習とAIは厳密は異なること
  • 特徴を理解する / 差異を区別すること を機械が自律的にできるようになることが今で言うところの人工知能的な何かであること

ということを知ることができただけでも、最近の動向なり、流行りを大分整理できました。

AIにどういう姿勢で望んでいけばいいか

僕の立場としては「ふーん」程度にまずは時代の流れをしっかり観察していこうと思います。
理由ですが、そもそも深層学習や人工知能と言っても、そのベースとなる特徴を理解させるには、大量かつ自分たちの意図するデータが返ってくるような特徴的なデータが必要で、これを学習させるのには大変なコストが掛かるので、おいそれと手を出せないと考えています。
そして

  • 意図するデータを返すための特徴的なデータ

は自分たちで用意する必要があり、学習させる際もパラメータをチューニングしていく必要があって、それは現状、初期段階では人力が必要になりそう。

そのため、一口に人工知能とか言っても、じゃあそもそも何に使って、そのためにどういうデータが必要なのかということがわからないと「人工知能なんで使うんだっけ?」っていうことになりかねないと考えています。

では、一般的なデータについてはおそらくですが、Googleだったり、Facebookだったり、Amazonだったり、すでに大量のデータを持っている企業にはそもそも量的な意味で勝負できないので、となると彼らが開発したAIを使うことのできるAPIを使って何ができるのか、それはビジネスに対してどういうインパクトがあるのか、そういことを考えることができる方が大事。

そういったことを考える機会になった本でした。

仕組みを理解したり、実際に作れることも大事ですが、こういう非連続的にポッと出てくる技術って世界を変える可能性がある反面、それに対して自分はどういう態度で望むべきなのか、ということを考えさせられます。
背景も含めて正確に理解することで、今後何が来て、どうなっていくのか、その時自分はどういうレベルにいればいいのか。
文系出身でニューラルネットワークについて全く理解していない自分でも、なんとなく概要を理解できたので、機械学習やAIについて漠然とした不安を持っているのであれば一度通読してみるといいかと思います。

ソースコードの検索の仕方

先に注意事項を書いておきます。

  1. コピペの仕方を書いているわけではありません。
  2. ソースコードの検索は実装の手助けをするものです。
  3. その前段階で設計や実装の準備はしっかり行っておく必要があります。

上記3つをこの記事では意識しています。

ソースコードを探すユースケース

ある特定の実装を想定する時に、どうやって実装するのかを考えます。
また、同時に、同じようなことをしているツール、ライブラリがないかを調べます。

誰かが似たような実装をしていたり、似たようなツールがあるので、あれば、そちらを使った方が実装工数は少なくて済むので楽です。

しかし、例えば、特定のライブラリを実装したい時に、ドキュメントだけでは実装方法がわからない場合があります。

ドキュメントに常に実装方法が記載されていれば言うことはありませんが、そうではなかったり、メジャーバージョンアップしたてのライブラリなどは、そもそも実装方法自体が世の中に出回ってなかったりすることが多々あります。

ドキュメント読んでもわからず、ぐぐっても求めているような実装コードが出てこなかったりするような場合を想定しています。

Githubソースコード検索

そういう場合に役に立つのが、Githubソースコード検索です。

Githubには上部にリポジトリやら、ユーザーを検索できる検索バーがありますが、実はこれ、ソースコードも検索できます。
※ 当然ですが、検索対象になっているのは、publicになっているリポジトリソースコードのみです。

「Swift ◯◯(ライブラリ名とか、メソッド名とか、名前空間とか) 」を入れて検索して、左のナビゲーションのところに、書かれている言語一覧が出てくると思いますが、この言語一覧をクリックすると、その言語で書かれたソースコードが表示されます。

どういった時に役に立つか。

ライブラリのマイナーな機能を使ったり、出たばかりのツールのコードを調べたりっていうのに僕は使っています。

そもそも実装方法が世の中に出回っていなくとも、世界の誰かが実装していたりするので、その誰かの知恵を拝借したり、参考にしたりするために使っています。

しかし、冒頭にも述べたように、それはあくまで、設計が完了して、どういったコードを書けばいいのか頭に浮かんでいるという前提があります。
そもそも、検索対象のコードの該当箇所しか検索結果にはヒットしませんので、一部分を切り出したところでなんの約にも立ちません。

しかし、どういったコードを書けばいいのかわかっていたり、実際にライブラリのソースコードを眺めて、どこでどういうメソッドを使えばいいのか頭に浮かんでいる人には、どこかの誰かが書いたコードは非常に有用です。

ライブラリの使い方で悩んで時間をかけるくらいなら、検索手段の一つとしてGithubソースコード検索を使ってみるのも一つのアイデアだと思います。

拡散思考と実装前提思考

ビジネスサイドや企画サイドと新機能や要望のやり取りをするときに、最近否定的な態度を取ってしまうことが多く、良くない傾向だとおもったので、そもそもなぜ否定的に考えてしまうのかということの理由を考えてみました。

拡散思考と実装前提思考

1. 拡散思考とは?

機能やアイデアを考える時に、納期や機能の実装を前提とせず、思いつくままにアイデアを拡散させていくこと。
実装前提ではないので、今のスキルレベルや実装の詳細を考えずに、自由な発想でサービスに向き合うことができます。

2.実装前提思考

機能の実装に納期が決まっており、実装、検証、改善のサイクルを回すことを前提とし、詳細を決めるために収縮していくこと。
実装される機能には、恒久的な機能とアドホック的な機能の2パターンがあるものの、どちらにせよ、開発が必要になるので、やることやらないことを明確に定義し、仕様に落とし込むことが必要になる。

コミュニケーションの前提を整える

新機能やアイデアに対して否定的になることが多く、コミュニケーションに齟齬が生まれていると感じるときは、この拡散的思考なのか、実装前提思考なのかのコンセンサスが取れていないことが多いのではないかと考えるようになりました。
エンジニアである以上、何か発案をもらったら、実装前提で考えることが多く、そのために、機能の詳細や、いつまでに、何を、どこまで実装するのかを正確に知ろうとしてしまいます。
この過程で、今やるべきなのか、代替案はないのか、そもそも必要なのかをしつこく確認することになり、それが、発案側としてはアイデアを否定されてしまっているように感じてしまうことがあると思います。

しかし、実装前提の立場に立った場合、大雑把な仕様だけでは、出戻りが発生する可能性が高く、どうしても、最速で実装するための最低のシステム要件は確認したくなってしまいます。
特に相手の実装を否定しているという意図はなく、それぞれに抱えているタスク、コミットするべきスケジュールがあるはずなので、それを優先するべきで、差し込みで入ってくる業務等にはどうしてもネガティブにならざる得ません。

拡散思考であれば、上がっているアイデアに対して、エンジニア目線で色んなフィードバックができるようになります。

つまり、大事なのはコミュニケーションを取る前段階で、実装前提なのか、拡散思考なのかはしっかり確認しておくことなのかなと

自分もコミュニケーションを取る際には、拡散思考なのか実装前提なのかを確認し、拡散思考であれば提案者のアイデアに寄り添うこと、実装前提であれば、スケジュールや詳細な仕様も加味しながらになるので、100%提案者のアイデアは汲み取りきれないことを伝えて、コミュニケーションの齟齬をを減らしていきたいものですね。

エンジニアのキャリアとして思うこと

エンジニアとしてのキャリアを今後どうしていくか、どうあるべきかの現時点を記録していこうと思います。

自分なりのエンジニアキャリアの考え方

一般的なエンジニアのキャリアの考え方は3種類あると思っています。
それは

  1. 技術突き詰める
  2. 技術をわかった上でビジネスする
  3. そのハイブリッド

の3つ。

では自分なりにどういうキャリアを歩んで行きたいのかって考えると、ずっと2だと思っていたんですが、最近は3も面白ろそうと感じるようになってきました。

なぜそう感じるようになったのかというと、単純に物作り、サービス作りって楽しいな、もっと大きくした時に、更に大きなフェーズで自分なりにモノづくりを楽しみたいなという思いができてきているからだと考えています。
エンジニアのスキルを持って、ビジネスをするのももちろん楽しそうですが、僕はまだ実感としては、コードを書く現場から離れずにサービスもグロースさせていきたいという思いが強いです。

なにより一つできるより複数のことをできた方が楽しいかなと。

今どうしていきたいか

技術もビジネスもできるハイブリットなキャリアを考える上で、「今」自分がどうしたいのかを考えてみると、今は「技術」に寄っている実感があります。

ビジネスをグロースさせる。
まだ見ぬ勝ちパターンを追求して、サービスが圧倒的に伸び始めている機会を体験したいという欲求はありつつも、伸びた先で待っているであろう課題解決をするためのスキルを今はとにかく身につけたいです。

使える言語やフレームワークへのこだわりはありませんが、少なくとも新しいシステムに触れることで、自分のキャリアの幅は広がり、解決できる課題も増えていくので、今はその課題の解決手段のパイを増やす作業をしていきたいです。

キャリアに課題を感じたときの指針

エンジニアとしてのキャリアを考えるに当たって、何か壁にぶつかったり、想定外の事態が起きて、自分の方向性に迷いが生じることがあります。

そういった時に、自分が提供しているサービス、プログラムが現実の生々しい課題に対して、どう切り込んでいるのかという感覚は捨てずにいきたいと考えています。

理由は、サービスはユーザーがいてこそ成り立つもので、ユーザーの趣味嗜好はこの時代、常に変化していきます。
そうした時に、ふとユーザーの方向や世の中のサービスの方向が変わった瞬間に顕在化するニーズを如何にはやくキャッチアップして、課題を解決するのか、その感覚を忘れずに行きたいなと思います。

サービスは生物であり、それを動かしているコードも生物です。
ニーズが変わればコードはそれに合わせて変わります。

エンジニアリングは課題解決が主たる業務なので、日々刻々と変化する市場とそれに対応するサービス、それを作っているコードが現実の課題に向き合っているのかどうか、そういう指針を持っていきたいと考えています。

今後どうしていきたいか

やはりサービス作りの現場にいたい気持ちがまだまだ強いです。
一方でソフトウェアだけの世界には限界があるように感じてもいます。

これからはオンラインだけでなく、オフラインでもサービスを起点として、ユーザーが繋がって、新しい行動を起こす、新しい価値観が生まれる、そういった世界観を作っていく仕事をエンジニアリングの領域をメインとしつつも関わっていきたい。。

エンジニアリングはどんな課題解決にも適用できると考えていて、サービスを作るだけでなく、そのサービスを支える全てのボトルネックの解消に適用できると考えています。
新しいツール導入したり、単純作業を自動化して、組織のパフォーマンスをあげたり等…

エンジニアリングはあくまで手段で、目標に向かっていく上で、その手段を用いて解決できること全てにエンジニアリングという武器として取り組んでいきたいと思っています。

スキルスタックにとらわれない、もっとメタな枠組みでのエンジニアリングの適用とでも言うのでしょうか。
そういった領域にすごく興味がありますし、良いサービスを作る上ではやっていきたいなと考えています。

iOS開発の学習に際して意識したこと

年明けから業務でiOS開発を担当することになったので、ここ一ヶ月半で何をして何をしなかったのかを書きます。

目標

一ヶ月でiOS開発に必要な知識のベースをつける

キャッチアップしないと行けなかったこと

  • Swift
  • Xcode
  • Cocoaプログラミング
  • Rx (含むリアクティブプログラミング)
  • 1通りObjectice-Cが読める

やったこと (最初の一週間)

ここで課題が発生します。
眠くなります。

ただ、トリセツ読んでるだけでは集中できずにすぐ眠たくなることがわかりました。
そこで手を動かそうと思います。

やったこと(次の一週間)

Appleの公式チュートリアル「Jump Right In」

これがすごく良かったです。
Xcodeの使い方からViewControllerとViewの関係、TableViewControllerまでの実装を学習できるのと、TableViewControllerがわかるとおおよそのアプリがどう作られているのかがわかるようになりました。
あくまで主観ですが。

これを一周完了した後にRxの学習をしました。
そしてつまづきました。

その段階で気づいたこと

  1. swiftを100%理解していない
  2. xcodeの操作で迷うときがある
  3. RxSwiftを理解するにはFRPをなんとなく理解する必要がある
  4. Cocoaプログラミングおろか、まだxcodeの使い方すらおぼつかない。

つまりまずやるべきは

  1. 開発にすぐ入れるレベルでのswiftの理解
  2. xcodeの使い方で迷わない

でした。

僕に限らず初学者にありがちなのが、開発環境構築や開発に必要なツールの理解が甘くて、挫折すること。
僕もその一人ではありますが、業務で行うにあたって挫折は許されないので、まずは開発環境の理解とswiftの理解に重きを置くことにしました。

んでそのタイミングでやることを絞り、

  1. xcodeとswiftの理解をすること

を最重要項目として

  1. Jump Right Inを何も見ずに作りきれるレベルで暗記する
  2. Swift 実践入門を読む
  3. CocoaプログラミングでJump Right Inに出てくるものは暗記する

でした。
優先順位としては

Swift > Cocoa >それ以外

って感じで進めることになります。

やったこと(残りの期間)

残りの期間はとにかく「Jump Right In」をひたすら写経。
わからないAPIAppleの公式リファレンスを読む。
幸いにして、Google翻訳ニューラルネットワークが導入されて翻訳精度が劇的に向上していたので、分からない分をそのまま邦訳かけても大意をつかめるところまでは可能でした。

上記を繰り返しておそらくですが、Jump Right Inは5〜6回くらい、公式リファレンスもわからないところは何度も調べたので、おおよそリファレンスのみかたや、実際にxcode上でAPIのソース読んだりとiOS開発にあたって必要なことを一気に頭に詰め込みました。
何度かやっているとswiftのお作法やappleのお作法も勝手にインプットされるので、いちいち確認することなく、とりあえずコーディング規約や言語仕様は当たり前だよねという感じで理解できるようになり、swiftも読めるようになってきました。

気づき

受験勉強しているときみたいでしたが、未経験のスキルを学ぶ時に、躓く箇所として

  1. ツールの使い方
  2. 開発環境の理解
  3. ググり方

っていうのはおおよそ共通して躓くところではないかと思います。
そこで、言語の仕様の理解と開発環境の使い方の理解に重きをおいて、短期間に一気に詰め込むっていうのは案外自分に向いている学習法であることに気づきました。
1ヶ月という比較的猶予を与えられていたので、スケジュールを微調整しながら学習することはできました。
とは言え、反省点も多く、最初に色々寄り道しなければもっと色んな学習をできたのではないかなと思います。

何か新しく学習することは、この仕事についている以上避けられず、また、いつ何時そのタイミングが訪れるかわかりません。

特に僕はエンジニアとしてのスキルはまだまだなので、多少効率が悪く、また、同じことの繰り返しで不安になることもありますが、そこは我慢して、どうすれば最短で業務に入れるのか、業務に入った後も自走しながらiOS開発をキャッチアップできるのかを考えて、今回のような学習をしました。
今は一通りのコードは読めるようになってきたので、多少なりこの学習方法は自分にあっていたのかなと思います。
学習に必要な期間、スキル、OJTなど、置かれた環境で異なると思いますが、学習方法の一つとして、写経を繰り返すっていうのは有効です。

※今はRxの理解が追いつかずつらい…

UIStackViewの削除に関しての追加学習

以前書いたカスタムUIStackViewクラス内の子要素を削除するの追記

  1. removeArrangedSubview()
  2. (UIView).removeFromSuperView

の動作の違いとなぜ2つのメソッドを使わないと完全に削除できないのかということについて。

removeArrangedSubview
https://developer.apple.com/reference/uikit/uistackview/1616235-removearrangedsubview

removeFromSuperview
https://developer.apple.com/reference/uikit/uiview/1622421-removefromsuperview

removedArrengedSubView addArrangedSubviewで追加したviewのみ削除する。しかし公式リファレンスによると

However, this method does not remove the provided view from the stack’s subviews array; therefore, the view is still displayed as part of the view hierarchy.

stack’s subview arrayは削除できない。 この stack’s subview array が残る。

そもそも stack’s subview array とは何か?

removeArrangedSubview(削除対象UIView)メソッドが動作して削除するとき

stack’s sarrangedSubview → 削除できる。 stack’s subview → 削除できない。

という動作がある。

  1. arrangedSubview → https://developer.apple.com/reference/uikit/uistackview/1616235-removearrangedsubview
  2. subview → https://developer.apple.com/reference/uikit/uiview/1622614-subviews

arrangedSubviews は subview の 配列の 集合体 add した時は stack view が subview としてこの arrangedSubview を追加する
remove した時は stack view が arrangedSubview の配列を削除する。
このとき、もともとの stack view の subview は削除しない。
階層構造として、stackview に紐づくarrangedSubview は削除するけど、stackview に紐づく subview は削除してくれない。

stackview
  subview
    arrangedSubview

という階層構造になっているのだと思う。storyboard上に出てこないのでわからない…
なので、removeArrangedSubviewした時に stackview 直下の subview は残るので、このsubview も removeFromSuperView() メソッドで参照を切り離さないといけない。

removeArrangedSubview(削除対象UIView) の後に (削除対象UIView).removeFromSuperView を使うのは公式リファレンスでも書かれているので、一般的な方法なのだと思う。

To prevent the view from appearing on screen after calling the stack’s removeArrangedSubview: method, explicitly remove the view from the subviews array by calling the view’s removeFromSuperview() method, or set the view’s isHidden property to true.

(削除対象のUIView).removeFromSuperview or (削除対象UIView).isHidden = true で残っているStackview を削除 or 非表示にする必要がある。

PhotoLibraryから画像を選択して画面に描画する実装

画像を選択してUIImageに表示させるという処理を実装します。

手順

UIImagePickerControllerDelegateUINavigationViewControllerDelegate を実装したViewControllerに継承させます。

UIImagePickerControllerDelegate…UIImagePicler → Libraryから画像を取得(pick)するためのViewController UINavigationControllerDelegate…画像を 取得するControllerに遷移しているのUINavigationViewContorollerを介して(動作としてはUINavigationViewController)いるので、この動作を対象のViewControllerに移譲する。

UIImagePickerControllerDelegateを継承することで、

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {}

の2つのメソッドが対象のViewControllerで利用できるようになる。

上記2つのメソッドについては Cancel は写真ライブラリから戻るときだとわかりやすい。

imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) のメソッドは UIImagePickerControllerDelegate プロトコルの持っているメソッド。

公式リファレンスはこちら
https://developer.apple.com/reference/uikit/uiimagepickercontrollerdelegate/1619126-imagepickercontroller

第一引数 picker … The controller object managing the image picker interface. ピックアップする動作(interface)
第二引数 info : Dictionary…
A dictionary containing the original image and the edited image, if an image was picked; or a filesystem URL for the movie, if a movie was picked. The dictionary also contains any relevant editing information. The keys for this dictionary are listed in Editing Information Keys.

originalImageとeditedImageをdictionaryが持っている。
JumpRighitInではoriginalimageを使っている。

UIImagePickerControllerOriginalImageの公式リファレンスは以下
https://developer.apple.com/reference/uikit/uiimagepickercontrolleroriginalimage

let UIImagePickerControllerOriginalImage: String

UIImagePickerControllerOriginalImage はImageと付いているが、UIImageを取り出すためのKey。
infoにKVSでUIImageが格納されている。

infoに保存されているUIImageのdectionaryでvalueを取り出すためのキーの一覧
https://developer.apple.com/reference/uikit/uiimagepickercontrollerdelegate/editing_information_keys

公式のリファレンス見ると、iOS側のimagePickerControllerで用意されているものが多く、普段使っているアプリ内の画像選択でも似たいような処理になっているところは多いので、イメージしやすかった。

コードからTableViewのeditボタンを生成する

UINavigationViewControllerをEnbedInしている状態で編集ボタンをコードから生成する。

navigationItem.leftBarButtonItem = editButtonItem

これで該当NavigationControllerを設置している箇所に対して、左上に編集ボタンを配置できる。

また、TableViewControllerで、

// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    // Return false if you do not want the specified item to be editable.
    return true
}

// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        // Delete the row from the data source
        tableView.deleteRows(at: [indexPath], with: .fade)
    } else if editingStyle == .insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }
}

上記箇所のコメントアウトを外す。

// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    // Return false if you do not want the specified item to be editable.
    return true
}

編集可能にする上記はTrueにする。

NSCodingのinitについて

さまり

Jump Right In でNSCodingを初期化する時に required と convenience を使って初期化している意図がわからなかったので調べた話

NSCodingの初期化について

公式のリファレンス https://developer.apple.com/reference/foundation/nscoding/1416145-init

init(coder:)
Required. Returns an object initialized from data in a given unarchiver.

NSCodingのinitの実装箇所にジャンプしても require 修飾子はついていなかったものの、公式リファレンスには、require が必須と書いてあった。

NSCoding は2つのメソッドの宣言を必要とする

  1. encode(aCoder: NSCoder) → KVOで値を保存(Archive)する
  2. init(aDecoder: NSCoder) → KVOで保存した値を解凍(UnArchive)する

上の2つのメソッドを宣言することでモデル層でKey Value Object形式であたりをアプリ内に保存します。

UIViewControllerのprepareメソッドについて

さまり

  1. prepareメソッドが理解できずにいた件
  2. swiftの外部引数と内部引数について

prepareメソッドが理解できずにいた件

prepare(for: ,sender:)メソッドがなかなか理解できずにいて、ようやく理解したので、その備忘録です。

まずprepare(for: ,sender:)について公式のリファレンスでは以下のように記載されています。
公式リファレンス

prepare(for:sender:)
Notifies the view controller that a segue is about to be performed.

func prepare(for segue: UIStoryboardSegue, sender: Any?)
// segue ... The segue object containing information about the view controllers involved in the segue.
// sender ... The object that initiated the segue. You might use this parameter to perform different actions based on which control (or other object) initiated the segue.

訳すと、segueが動作することをViewControllerに通知するということ。
取る引数については
segue : 動作するsegue
sender : 次のViewControllerに送信するObject(Any?だからなんでも送れる)

んで何がわからなかったかというと、メソッドのリファレンスにある (for segue: UIStoryboardSegue, sender: Any?) っていうかしょ。
for ってなに?っていうのが最初に抱いた疑問でした。

実装コードの中で親クラスの prepare メソッドを呼ぶ時に

super.prepare(for: segue, sender: sender)

って記述があって、最初のほう、頭混乱してました。
で結果なんですが、これ外部引数と内部引数なんですね。

外部引数と内部引数について

swiftはメソッドの呼び出し時に使用する外部引数と、メソッドの内部で利用する内部引数の2つを持つことができます。
外部引数と内部引数を分けるためには、 外部引数名 内部引数名 : 型 と書き方をします。
prepareメソッドで prepare(for segue: UIStoryboardSegue, sender(Any?)) と記載されていた箇所ですが、

for : 外部引数
segue : 内部引数

だったわけです。そのため、swiftでメソッドをドキュメント等で記載する時に prepare(for:,sender:) という書き方をしていたわけです。
ドキュメント等への書き方の場合は、外部引数を使います。
外部引数と内部引数がわかると、segue という変数はメソッド内部で変数の振る舞いがわかりやすいから内部引数と外部引数で分けています。
swiftでは可読性を上げるために、外部引数と内部引数を併記する場合があります。

例えば、ユーザーを特定のグループに招待するというメソッドを考え見ると

func invite (user : String, to group: String) {
    print("\(user)\(group)に招待します。")
}

となります。 この場合このメソッドをコールするときには

invite(user: "Taro", to: "Swift")

となり、誰をどのグループに呼んだのか、メソッドからわかり、可読性が上がります。
ただし、inviteメソッド内部では、変数が to のままではメソッド内部の振る舞いがわかりづらいので、メソッド内部では group という変数を使ってメソッド内部での可読性もあげています。

使うと非常に便利ですが、まだ、外部引数と内部引数を分けたコードについて、読み慣れていないので、prepareメソッドの理解の部分でハマりました。

emacsのパッケージをcaskで管理する上で気をつけていること

emacs のパッケージ管理

  • emacs 25.1
  • cask を使ってパッケージの管理をしていたりします

一応githubemacsのパッケージリストは公開中
my emacs conf

えぐさま

  1. Vagrantで立ち上げた仮想環境でcaskが動作しない
  2. Macでcaskを入れる場合とcentOSでcaskを入れる際の手順が違っていた
  3. centOSでcaskを入れる
  4. 作成済み.emacs.dのディレクトリ内にあるCaskを使ってパッケージをインストールする

手順とハマったところ

手順

  1. centOSyumemacsを入れる
  2. centOSにcaskを入れる
  3. caskでパッケージをインストールする

centOSyumemacsを入れる

まず最初にここでハマりました。

$ sudo yum install -y emacs
# emacs 23.* がインストールされてしまう

yumで管理されているemacsのパッケージが古く、自分の用意したemacs のcaskで管理しているパッケージが25.1用だったので、cask登録時にバージョン違いのエラーが起こりました。

そこでcentOSemacs 25.1 を入れます。
yumで入れられないので、ソースからコンパイルします。

このあたり参考にしました。
Installing Emacs 25.1.1 on CentOS 6.8

$ sudo yum install -y xz
$ curl http://core.ring.gr.jp/pub/GNU/emacs/emacs-25.1.tar.xz | tar Jxf -
$ cd emacs-25.1/
$ ./configure --without-x
$ make
$ sudo make install
$ emacs --version
GNU Emacs 25.1.1
Copyright (C) 2016 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.

caskをインストールする

Macではbrewで提供されているので、brew入れた後にパス通してくれますが、centOSはソースからビルドするので、パスを通す必要あり。

$ curl -fsSL https://raw.githubusercontent.com/cask/cask/master/go | python
$ export PATH="$HOME/.cask/bin:$PATH"

ここでcaskのファイルはリポジトリの中にある
caskのコマンドを実行した時に、すでにインストールしていた.emacs.d のディレクトリ配下の.cask以下にコマンドを移動する

caskでパッケージ入れる

# コマンドは以下
$ /.cask/.cask/bin/cask
$ cd .emacs.d/
$ cask
# cask-bootstrap cask-cli cask がなくcaskが実行できない
# この状態でemacsを起動するとcaskがないと言われて起動できない

Macbrew経由でcaskを入れた場合はこのあたりをよしなにしてくれていたけど、CentOSでソースから入れた場合はcaskの立ち上げ*.elファイルを.emacs.d/.cask配下に置かないとcaskが起動しない。

$ cd
$ cp .cask/cask-bootstrap.el ../.emacs.d/.cask/
$ cp .cask/cask.el ../.emacs.d/.cask/
$ cp .cask/cask-cli.el ../.emacs.d/.cask
$ cd ../.emacs.d/
$ cask
# これでcaskが実行されてパッケージが入る

カスタムUIStackViewクラス内の子要素を削除する

UIStackViewとは?

iOS9から導入された概念
UIView郡をUIStackView内に入れ子として管理できる。
UIStackViewが親でUIButtonなどの各UIパーツが子要素になる。

Apple公式チュートリアル内でボタンを削除する

JumpRightIn

対象となるコードはこちら(抜粋)

private var ratingButtons = [UIButton]()

// clear any existing buttons
for button in ratingButtons {
    removeArrangedSubview(button)
    button.removeFromSuperview()
}
ratingButtons.removeAll()

UIStackViewの削除

メソッドの一つ一つ動作

  1. removeArrangedSubView でUIStackViewに割り当てられているUIパーツの配列から該当UIパーツを削除する
  2. burron.removeFromSuperview でSuperViewからUIButtonの参照を外す
  3. ratingButtons.removeAll() で配列を空にする

arrangedSubview はSubview(ここではUIStackView)に組み込まれたViewのこと。公式チュートリアルでは星型のUIButtonがこれにあたる。
このarrangedSubview は中に配列としてUIパーツを持つので、最初に対象のUIパーツをこの配列から外す。
次に、removeFromSuperView で対象のUIパーツの参照を親のViewから外す。

これで参照されるUIパーツがUIViewから削除されて新しくボタンを定義できるようになる。

参照 メソッドの意味

iTermのブルーが見づらかったので調整した話

iTerm2で青色がすごく見づらかった…

iTerm2で作業する時に青が見えづらくてしかたなかったので、青の文字の色彩を調整しました。
調整の仕方は、iTerm2の設定(Cmd + ,)を開いて、Profile -> Defauktの外観の設定 -> Colorを選択
Minimun Contrastを調整して、コントラストをいい感じにすると背景の黒と青文字のコントラストが変わって見やすくなります。

Markdownを書こうとしたり、ターミナルでディレクトリ見たりする時に大体、青色がものすごく見づらかったので、非常に目に優しくなりました

image