【完全保存版!】iOSエンジニアとして働く上で知っておきたい14のこと
![](https://thinkit.co.jp/sites/default/files/styles/main_image_730x/public/main_images/1-dLNPhFL6k2MFJBAm9g24UA-620x286.png?itok=fCG0x_w2)
本稿は、Swift Sailingのブログ記事を了解を得て日本語翻訳し掲載した記事になります。
本記事は、iOS開発者のNorberto Gil Vasconcelos氏によって投稿されました。
iOS開発者として、現在私はSwiftに夢中です。私はゼロからアプリを開発し、アプリを保守運用し、多くの異なるチームで作業をしてきました。
IT業界にいるとき私は常に、次の言葉を念頭に置いています。
「もしそれを説明できないなら、それを理解していない。」そのため、私は毎日行っていることを完全に理解するために、iOSデベロッパーにとって重要だと思われることのリストを作成しています。各点をなるべく明確に説明しようと努めました。
iOSエンジニアが知っておきたい14のこと
- ソースコード管理
- アーキテクチャパターン
- Objective-C vs. Swift
- リアクティブにすべきかどうか
- 依存関係管理ツール
- 情報を格納する
- コレクションビュー&テーブルビュー
- ストーリーボード vs. XIB vs. プログラマティックUI
- プロトコル
- クロージャ
- スキーム
- テスト
- 位置情報
- ローカライズ可能な文字列
1. ソースコード管理
あなたがエンジニアとして雇用されることが決まったとします。
最初にすることは、リポジトリからコードを取得して作業を開始することです。しかし、ちょっと待ってください!
あなたがチーム内で唯一のエンジニアであっても、すべてのプロジェクトはソースコード管理を必要とします。最も一般的な方法は、GitとSVNです。
SVN
SVNは、バージョン管理のための集中型システムです。これは、作業コピーを生成し、アクセスにはネットワーク接続を必要とする中央リポジトリです。
アクセス許可はパスベースであり、ファイルを登録することによって変更を追跡し、変更履歴はリポジトリ内でしか完全なものを見ることができません。作業コピーには最新バージョンのみが含まれます。
Git
Gitは、バージョン管理のための分散型システムです。ネットワーク接続で同期すれば、ローカルのリポジトリを使用して作業することもできます。
アクセス許可はディレクトリ全体に及び、コンテンツを登録することによって変更を追跡し、リポジトリと作業コピーの両方が完全な変更履歴を保持します。
2. アーキテクチャパターン
さて、あなたはソースコード管理を理解できたら、興奮してドキドキするかもしれません!それともコーヒーの影響でしょうか?どちらでも関係ありません!次は、あなたは集中してコードを書く段階です!いいえ、まだです。ちょっと待ってください!
キーボードを打つ前に、配置するアーキテクチャパターンを選択する必要があります。プロジェクトを開始していない場合は、実装されているパターンに準拠する必要があります。
MVC、MVP、MVVM、VIPERなど、モバイルアプリ開発において使用されるパターンにはさまざまなものがあります。ここでは、iOS開発で最も一般的に使用されているパターンの概要について、簡単に説明します。
MVC
モデル、ビュー、コントローラの略です。
コントローラは、モデルとビューを橋渡しする存在であり、モデルとビューは互いを認識することはありません。ビューとコントローラの間の関連は非常に強固なので、コントローラがすべてを処理することもあります。
このことは何を意味するのでしょうか?
簡単に言うと、複雑なビューを構築する場合、コントローラは不必要に大きくなります。これを防止する方法もありますが、MVCのルールに反するものです。MVCのもう一つの欠点は、テストです。あなたがテストを実行するとしたら、おそらくモデルを単体でテストすることになります。というのも、モデルは残りの他の層とは別の層であるからです。
一方、MVCパターンを使う利点は、直感的で、ほとんどのiOS開発者がそれに慣れていることです。
MVVM
モデル、ビュー、ビューモデルの略です。
ビューとビューモデルの間でバインディングが設定されると、これによりビューモデルはモデル上の変更を呼び出すことが可能になります。次にモデルはビューモデルを更新し、バインディングによってビューも自動的に更新されます。
ビューモデルはビューについて何も情報を持たないため、テストやバインディングが容易になり、多くのコードを減らす効果があります。
他のパターンについては、次の案内をお勧めします。
このことはあまり重要性がないように思えるかもしれませんが、構造化され整理されたコードは多くの問題を防ぐことができます。
すべてのエンジニアがある時点で犯す大きなミスは、時間節約の効果があるという錯覚の下、目標とする結果を得るためにコードの整理を疎かにすることです。
もしまだ納得できない場合には、次のベンジャミンの名言を考えてください。
整理に1分間の時間を投資するごとに、1時間を得られる。――ベンジャミン・フランクリン
目標は、直感的で読みやすいコードにすることです。これにより簡単に構築して管理することが可能です。
3 . Objective-C vs. Swift
あなたのアプリをプログラミングする言語を決めるときは、各言語がもたらすメリットを知る必要があります。もし選択肢の余地があるとしたら、私は個人的に、Swiftを使用することをおすすめします。正直なところ、Objective-CがSwiftと比べて優れている点はほとんどありません。
たしかに、ほとんどのサンプルとチュートリアルはObjective-Cによって書かれています。
また、Swiftでアップデートのたびにプログラミングパラダイムが調整されていることには、がっかりするかもしれません。しかし、これらは長期的には解決される問題です。
Swiftは本当に多くの点で優れています。読むのは簡単で、自然な英語に近く、C言語を継承していないため従来の慣例は消えています。 Objective-Cをすでに習得した人にとってこれは、セミコロンがないこと、メソッド呼び出しに角括弧[ ]は不要であること、条件式を囲む丸括弧( )は不要であることを意味します。
また、コードの管理もより容易です。 XcodeとLLVMコンパイラは依存関係を把握し、インクリメンタルビルドを自動的に実行できるため、Swiftは「.h」と「.m」拡張子ファイルの代わりに「.swift」拡張子ファイルしか必要としません。全体的に、定型コードを生成することについてあまり心配する必要もなく、より少ないコードで同じ結果を達成できます。
より安全で、より速く、メモリ管理に優れているのはSwiftです。
Objective-Cで初期化されていないポインタ変数を持つメソッドを呼び出すとき、何が起こるかを知っていますか?何も起こりません。式は操作不能になり、スキップされます。
このことは、アプリをクラッシュさせることがないという意味では素晴らしいですが、あなたのキャリアを考え直したいと思うような一連のバグと不規則な動作を引き起こします。
Swiftのカウントはこれをオプショナル型で実行します。何がnilになる可能性があるか、nilが確実に使用されないようにするにはどうしたらいいかを理解できるようになるだけではなく、Swiftはオプショナル型でnilが使用された場合に実行時クラッシュを発生させ、デバッグを容易にします。
メモリ的な視点から簡単に説明すると、ARC (自動参照カウント)は、Swiftの方が優れているということです。
Objective-Cの場合ARCは、手続き型のCコード、Core GraphicsなどのAPIでは機能しません。
4 . リアクティブにすべきかどうか?それが問題です。
FRP(関数型リアクティブプログラミング)は新しい流行のようです。その目的は、非同期操作とイベント/データストリームを簡単に構成できるようにすることです。
これを例証するために最も簡単な方法として、小さなコードを考えてみます。
少年ティミーと妹のジェニーが、新しいゲームコンソールを購入したいとします。ティミーは毎週両親から5ユーロ(600円)を得ます。ジェニーも同じです。
しかし、ジェニーは週末に新聞配達をすることでさらに5ユーロ(600円)を得ます。
もし彼らが二人とも1セント(1円)を節約した場合、コンソールが購入可能かどうかを毎週確認することができます。どちらか一人の貯蓄する金額が変化するたびに、彼らの合計金額が計算されます。購入するのに十分な額である場合、メッセージは変数「isConsoleAttainable」に保存されます。
いつでも、subscribeメソッドによってメッセージを確認することができます。
// Savings let timmySavings = Variable(5) let jennySavings = Variable(10) var isConsoleAttainable = Observable .combineLatest(timmy.asObservable(), jenny.asObservable()) { $0 + $1 } .filter { $0 >= 300 } .map { "\($0) is enough for the gaming console!" } // Week 2 timmySavings.value = 10 jennySavings.value = 20 isConsoleAttainable .subscribe(onNext: { print($0) }) // Doesn't print anything // Week 20 timmySavings.value = 100 jennySavings.value = 200 isConsoleAttainable .subscribe(onNext: { print($0) }) // 300 is enough for the gaming console!
以上は、FRPでできることについて表面的に触れました。
FRPは一度そのコツを理解すると、全く新しい可能性の世界が開き、一般的なMVCとは異なるアーキテクチャを採用することさえ可能です。
5. 依存関係管理ツール
CocoaPodsとCarthageは、SwiftとObjective-C Cocoaにおけるプロジェクトのための、最も一般的な依存関係管理ツールです。ライブラリ実装のプロセスを簡素化し、更新を行います。
CocoaPodsは豊富なライブラリがあり、またRubyで構築されており、次のコマンドを使ってインストールすることができます。
$ sudo gem install cocoapods
インストール後、プロジェクト用のPodfileを生成することになります。次のコマンドを実行できます。
$ pod install
または、次の構造を持つカスタムのPodfileを生成します。
platform :ios, '8.0' use_frameworks! target 'MyApp' do pod 'AFNetworking', '~> 2.6' pod 'ORStackView', '~> 3.0' pod 'SwiftyJSON', '~> 2.3' end
一度生成したら、新しいポッドをインストールします。
$ pod install
これでプロジェクトの.xcworkspaceを開くことができます。また、依存関係をインポートすることを忘れないでください。
Carthageは、CocoaPodsとは異なり、分散型の依存関係管理ツールです。ユーザーが既存のライブラリを見つけるのが難しくなるという欠点があります。一方、メンテナンス作業が少なくて済むのが利点です。
6. 情報を格納する
まずは、あなたのアプリのデータを保存する簡単な方法から始めましょう。
NSUserDefaultsクラスは、アプリが最初にロードされたときに取得される、デフォルトのユーザーデータを保存するために使用されるため、このような名前が付いています。これはシンプルで使いやすいものですが、いくつかの制約があります。
制約の1つは、受け入れるオブジェクトの型です。同じ制約を持つプロパティリスト(Plist)と非常によく似ています。格納できるオブジェクトは次の6つの型です。
- NSData
- NSDate
- NSNumber
- NSDictionary
- NSString
- NSArray
Swiftとの互換性を保つため、NSNumberオブジェクトは以下の型を受け入れることができます。
- UInt
- Int
- Float
- Double
- Bool
オブジェクトは次の方法でNSUserDefaultsに保存することができます。
let keyConstant = "objectKey" let defaults = NSUserDefaults.standardsUserDefaults() defaults.setObject("Object to save", objectKey: keyConstant)
NSUserDefaultsからオブジェクトを読み取るには、次のようにします。
if let name = defaults.stringForKey(keyConstant) { print(name) }
AnyObjectの代わりに特定のオブジェクトを取得するには、NSUserDefaultsへ読み書きをするための便利なメソッドがいくつかあります。
Keychain
Keychainは、パスワード管理システムであり、パスワード、証明書、秘密鍵または秘密のファイルを含むことができます。Keychainによるデバイス暗号化には2つのレベルがあります。第1レベルでは、ロック画面のパスコードが暗号化キーとして使用されます。 第2レベルは、デバイスによって生成されデバイスに格納されたキーを使用します。
これは何を意味するのでしょうか?まずあなたがロック画面のパスコードを使用していない場合は、安全性が非常に高いとはいえません。 第2レベルで使用されているキーは、デバイスに保存されているためアクセスされるおそれがあります。
最適な解決策は、独自の暗号化を使用することです。
CoreData
CoreDataは、あなたのアプリケーションがオブジェクト指向の方法でそのデータベースと通信するために、Appleによって設計されたフレームワークです。このフレームワークは、プロセスを簡素化し、コードを減らし、コードの該当部分をテストする必要性を省きます。
あなたのアプリに永続データが必要な場合は、このフレームワークを使いましょう。データを永続化するプロセスは単純化され、あなたはデータベースとやりとりするために独自の方法を、構築したりテストしたりする必要もありません。
7 . コレクションビュー&テーブルビュー
すべてのアプリには、1つ以上のコレクションビュー(CollectionView)および/またはテーブルビュー(TableView)があります。
これらがどのように動作するか、場合に応じてどちらを使用するべきかを知ることで、将来あなたのアプリの変更が複雑になるのを防ぐことができます。
テーブルビュー
テーブルビューは、アイテムのリストを単一の列に縦方向に表示し、縦スクロールのみに制約されます。各アイテムは、完全にカスタマイズすることができるUITableViewCellによって表されます。
これらはセクションと行にソートされます。
コレクションビュー
コレクションビューも、アイテムのリストを表示しますが、複数の行と列を持つことができます。横方向および/または縦方向にスクロールすることができます。各アイテムはUICollectionViewCellによって表されます。
UITableViewCellsと同様に自由にカスタマイズすることが可能で、セクションと行にソートされます。
これらは両方とも似た機能性を有し、流動性を高めるために再使用可能なセルを使用します。どちらを選択するべきかは、あなたのリストの複雑性によります。
私の意見では、コレクションビューはどんなリストを表現する場合にも使用することができて、常に良い選択であるといえます。
例えば、連絡先リストを表現したいとします。
これはシンプルなリストなので、1列で表現することができるため、あなたはUITableViewを選びます。優れた動作性です!しかしその数か月後、チームのデザイナーは連絡先リストを、リスト形式ではなくグリッド形式で表示することを決定しました。
これを行うには、UITableViewの実装をUICollectionViewの実装に変更するしかありません。
あなたのリストがシンプルでUITableViewで十分である場合でも、デザインが将来変更される可能性が高い場合は、リストをUICollectionViewで実装するのが最善ということです。
どちらを選択するとしても、ジェネリックなコレクションビュー/テーブルビューを作成することをおすすめします。そうすれば、実装が容易になり、多くのコードを再利用できます。
8 . ストーリーボード vs. XIB vs. プログラマティックUI
これらの手法はそれぞれ個別に使用してUIを作成することもできますが、組み合わせることもできます。
ストーリーボードでは、プロジェクトの幅広いビューが可能になり、これはアプリの流れとすべての画面を見ることができるので、デザイナーに好まれます。
欠点は、より多くの画面が追加されたときに接続が滞り、ストーリーボードの読み込み時間が長くなることです。 UI全体が1つのファイルに属しているため、マージするときに競合(コンフリクト)の問題が頻繁に発生します。 これは解決するのが難しいです。
XIBは、画面または画面の一部を視覚的に表示します。 利点は、再利用が容易であること、ストーリーボードによる手法よりもマージの競合(コンフリクト)が少ないこと、各画面に何が表示されているかを簡単に確認できることです。
UIをプログラミングすることで、多くのコントロールが可能になります。マージの競合(コンフリクト)の発生も少なくなり、もし発生したとしても簡単に解決できます。欠点は、ビジュアルエイド(視覚的な理解を促す画像、グラフなど)が欠如していること、プログラムに余分な時間がかかることです。
アプリのUIを作成するには、非常に異なる手法があります。しかし、私の主観的な意見ですが、最高の手法はこれら3つをすべて組み合わせることです。複数のストーリーボード、XIBはメイン画像ではないビジュアル、そして最後に、特定の状況で必要となる追加的な制御のためのプログラミングです。
9. プロトコル
私たちの日々の生活の中には、状況に応じて対処する方法としてのプロトコルが存在しています。たとえば、あなたが消防士で緊急事態が発生したとしましょう。すべての消防士は、的確に対処するための要件を設定するプロトコルに従わなければなりません。同じことがSwift / Objective-Cプロトコルにも当てはまります。
プロトコルは、与えられた機能を満たすメソッド、プロパティ、およびその他の要件の設計図を定義します。プロトコルは、クラス、構造体または列挙型に使用することができ、次にこれらの要件を実装します。
プロトコルを生成して使用する方法の例を次に示します。
私が先に紹介した例では、火を消すために使うことができるさまざまなタイプの道具を列挙する列挙型が必要です。
enum ExtinguisherType: String { case water, foam, sand }
次に、緊急事態に対応するプロトコルを生成します。
protocol RespondEmergencyProtocol { func putOutFire(with material: ExtinguisherType) }
今度は、プロトコルに準拠したクラスFireman(消防士)を生成します。
class Fireman: RespondEmergencyProtocol { func putOutFire(with material: ExtinguisherType) { print("Fire was put out using \(material.rawValue).") } }
すばらしいです!次に、このFiremanを行動に移させましょう。
var fireman: Fireman = Fireman() fireman.putOutFire(with: .foam)
この結果は「火は泡を使って消されました。」となります。
プロトコルは委任(Delegation)でも使用されます。クラスまたは構造体は、特定の関数を別の型のインスタンスに委任できます。プロトコルは、適合する型が代わりに機能を提供するよう保証するため、責任を委任できるように生成することができます。
簡単な例を示します。
protocol FireStationDelegate { func handleEmergency() }
FireStation(消防署)は、緊急事態に対処する措置をFireman(消防士)に委任します。
class FireStation { var delegate: FireStationDelegate? fun emergencyCallReceived() { delegate?.handleEmergency() } }
これは、FiremanがFireStationDelegateというプロトコルにも準拠する必要があることを意味します。
class Fireman: RespondEmergencyProtocol, FireStationDelegate { func putOutFire(with material: ExtinguisherType) { print("Fire was put out using \(material.rawValue).") } func handleEmergency() { putOutFire(with: .water) } }
呼び出されたFiremanが行わなければならないことは、FireStationを代理することであり、受け取った緊急の呼び出しを処理します。
let firestation: FireStation = FireStation() firestation.delegate = fireman firestation.emergencyCallReceived()
その結果は 「火は水を使って消されました。」となります。
見ての通り、プロトコルは非常に便利です。プロトコルでできることは他にも数多くありますが、取り敢えず私はここまでにしておきます。
10. クロージャ
ここでは、Swiftのクロージャ(Closure)だけに焦点を当てます。クロージャはほとんどの場合、completionブロックまたはより上位の関数を返すために使用されます。補完ブロックは、その名前が示すように、タスク終了後に、コードブロックを実行するために使用されます。
- Swiftのクロージャは、CとObjecdtive-Cのブロックに似ています。
- クロージャは、ネスト構造にして渡すことができます(Objective-Cのブロックと同様に)。
- Swiftでは、関数はクロージャの特別なケースにすぎません。
11 . スキーム
簡単に言えば、スキームは設定を切り替える簡単な方法です。
ワークスペースには、さまざまな関連プロジェクトが含まれています。プロジェクトにはさまざまなターゲットがあります。ターゲットは、ビルドする製品とそのビルド方法を指定します。
またプロジェクトにはさまざまな設定があります。 Xcodeのスキームは、ビルドするターゲットの集合、ビルド時に使う設定、実行するテストの集合を定義します。
12 . テスト
アプリのテストに時間を割くことができれば、あなたは正しい方向に進んでいるといえますが、それは万能の解決策ではありません。あなたはすべての単一のバグを防ぐことはできませんし、アプリに問題がないことを完全に保証することはできません。
しかし私は賛成論のメリットは反対論を上回ると思います。
ユニットテストの反対論から考えましょう。
- 開発の時間が増える
- コードの量が増える
賛成論
- モジュラーコードを強制的に作成することになる(テストを簡単にするため)
- 明らかに、より多くのバグがリリース前に検出される
- メンテナンスが簡単である
テストをいくつかの手法と組み合わせることで、バグとクラッシュのない優れたアプリを作成するツールをすべて揃えることができます。
あなたのアプリで何が起きているかを確認するために使うことができる手法は、数多くあります。あなたが確認したいことに応じて、それらを1つ以上選ぶことができます。
最も一般的に使用されているのは、おそらくメモリリークの検出、プロファイルのタイマー&メモリ割り当てです。
13. 位置情報
多くのアプリは、ユーザーの位置情報を要求する機能を備えています。そのため、iOSのロケーションの仕組みに関して一般的な知識を持っておくことは、良い考えです。
Core Locationと呼ばれるフレームワークがあり、必要なものすべてにアクセスできます。
「Core Locationフレームワークでは、デバイスに関連付けられている現在位置または見出しを特定できます。 フレームワークは利用可能なハードウェアを使用して、ユーザーの位置と見出しを決定します。
このフレームワークのクラスおよびプロトコルを使用して、ロケーションおよび見出しイベントの配信を、設定およびスケジュールします。 地理的領域を定義し、ユーザがそれらの領域の境界を横切るときに監視するためにも使用することができます。
iOSでは、Bluetoothビーコン周辺の地域を定義することもできます。 」(引用:AppleのCore Location概要より翻訳)
かなり魅力的なものに思えますか? Appleのドキュメントガイドとサンプルコードを読んで、あなたができることとその方法を理解してください。
14. ローカライズ可能な文字列
すべてのアプリが実装するべきものがあります。それは、アプリが使用される地域に応じて言語を変更するすることを、可能にします。あなたのアプリが1つの言語のみで始まっても、将来的に新しい言語を追加する必要が生じるかもしれません。
ローカライズ可能な文字列を使用してすべてのテキストを入力すれば、新しい言語用のLocalizable.stringsファイルの翻訳バージョンを追加すればいいだけです。
ファイルインスペクタから言語にリソースを追加することができます。「NSLocalizedString」で文字列を取得するには、以下が必要です。
NSLocalizedString(key:, comment:)
残念ながら、新しい文字列をLocalizable.stringsファイルに追加するには、手動で行う必要があります。構造体の例を次に示します。
{ "APP_NAME" = "MyApp" "LOGIN_LBL" = "Login" ... }
次に、これに対応する異なる言語(ポルトガル語)の、ローカライズ可能なファイルです。
{ "APP_NAME" = "MinhaApp" "LOGIN_LBL" = "Entrar" ... }
複数形を実装する方法さえあります。
常にあなたが学んだことを人に伝えるのだ。――ヨーダ
この記事があなたの役に立ったことを願っています。
TechAcademyでは初心者でも最短4週間でオリジナルアプリが作れるiPhoneアプリ開発オンラインブートキャンプを開催しています。期間中は現役エンジニアのメンターが毎日学習をサポートするので、独学よりも効率的に学ぶことができます。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- クリアコード、メールシステムテストのためのメールを共有するオープンソースプロジェクト「test-mailsプロジェクト」を開始
- テクマトリックスがC/C++対応テストツールの最新版「C++test 10.3.2」を販売開始
- マイクロフォーカス、負荷テストツール「SilkPerformer」とソフトウェアテスト管理ツール「SilkCentral Test Manager」の新バージョンをリリース
- Linux Test Project、Linuxテストスイート「JANUARY 2017」をリリース
- Linux Test Project、Linuxテストスイート「JANUARY 2017」をリリース
- テクマトリックス、組込みソフトウェア開発をサポートするC/C++対応テストツール「Parasoft C++test 10.4.1」の販売を開始
- テクマトリックス、C/C++対応テストツール「Parasoft C++test.10.4.3」の販売を開始
- テストスイート「Linux Test Project May 2017」リリース
- テストスイート「Linux Test Project May 2017」リリース
- オープンソースのAndroidアプリテストツール「Test Butler」リリース