iOSアプリ開発3日目
iOSアプリ開発の3日目では、カメラアプリを作成する。UIパーツの配置やプログラムとの関連づけなど基本的なところから、アプリがデバイスの機能(カメラ)を使用する際の管理などについてふれている。
前回の記事はこちら。
3日目の学習項目はこちら。
講座では10の項目に分かれているが、このエントリではこれを内容で5つに分けて勉強メモとする。
アプリ開発の大まかなフローは、以下のようになっている。
・(準備)開発環境を整える。アプリをリリースしたいのであれば、ライセンス登録をする。
→Xcodeでプロジェクトを作成(起動)
→Viewを作成し、オブジェクトを配置しUIを設定していく
→オブジェクトに処理を加える(ここでプログラムを書いていく)
→動作確認(ビルド&実行)
→リリース(するかしないかはあなた次第)
では、今回の学習内容に戻る。
1.UI設定
ナビゲータエリアからMain.storyboardを選択する。そして、View Controller下にあるViewを選択すると、実際にアプリで表示されたときのプレビューが表示される。Xcodeを用いた開発の大きな特徴は、このプレビュー画面に直接パーツを配置することで、直感的にアプリのUIを作っていけるところだと思っている。
スクショではすでにオブジェクトが入ってしまっているが、実際はまっさらな画面である。
次に、オブジェクトの挿入である。
Image Viewとすべて入力する前に、「ima」まで打つと「Image View」が出てくる。
オブジェクトをドラッグ&ドロップで、画面の好きなところに配置できる。
今回は、Image Viewを1つ、Buttonを2つ配置する。
そして、下記の①〜⑤の手順で追加したオブジェクトの見た目を設定する。
④のマージン設定は大切な作業である。iOSはiPhoneにしても毎年新しいデバイスが登場し、iPadなどもあることから、様々なデバイスでアプリを作動させても、崩れないデザインであることが求められる。
次は、配置したUIパーツとプログラムを関連づける。
※ Ctrlキー(コントロールキー)を押しながら、プログラム(ViewController.swift)にドラッグ&ドロップをする。
プログラムを入力した後にスクショしたので記述があるが、オブジェクトをドラッグ&ドロップしただけなのでここでは無視してほしい。
IBOutlet(アイビーアウトレット):Interface Builder Outlet(データの出力先)として設定する。ブジェクトをドラッグ&ドロップすると、以下のようなポップアップが出てきて設定ができるので、ConnectionをOutlet、NameをphotoImageとする。TypeをUIImageView、StorageがWeakになっていることを確認して、Connectを押す。
Swiftでは、英単語の1つ目は小文字表記にして2つ目以降の頭文字を大文字にする習慣(キャメルケース)があるようだ。アンダースコアでつなぐのはスネークケースと呼ばれているらしい。
オブジェクトとプログラムの関連付けが上手くいくと、プログラムに下記のような記述が追加される。
同様に他ボタンも追加していく。ボタンの場合のConnectionはAction、ArgumentsはSenderにしておく。
IBAction(アイビーアクション):Interface Builder Action(ボタンの処理)を行う関数が設定される。
2.カメラの起動確認の設定
講義では触れられていなかったが、まずInfo.plistを設定する必要があった。参考にした記事はこちら。
Custom iOS Target Propertiesというプロパティリストで、アプリ内のさまざまなアクセスを管理している。Required device capabilitiesでデバイスの利用が必要であるという設定項目。ここでカメラの設定を追加する。
3.実装
ViewController.swiftに①カメラにアクセスする処理、②①からデータを受け取って終了する処理、③SNSに投稿する処理の3つのコードを記述していく。
①カメラにアクセスする処理
これは、ViewController.swiftのコード記述前。
「カメラで写真を撮り終わった」もしくは「写真を選択し終わった」状態(イベント)を検知してひきわたすデリゲートという仕組みを実装していく。
class ViewController: UIViewControllerの後に、記述を追加していき、上画像の青く選択された部分のように変更する。
・UINavigationControllerDelegate 写真を撮り終わった
・UIImagePickerControllerDelegate 写真を選択し終わった
この二つを追記することで、写真を撮り終わった状態もしくは写真を選択し終わった状態を検知して、プログラム内容を実行する。
次に、「アプリを実行しているデバイスのカメラが利用可能か」「ユーザーがカメラ起動を許可しているか」を調べるための処理を追加していく。
UI設定で「カメラを起動する」ボタンからプログラムに入れた、「カメラローンチアクション」の中に記述する。
@IBAction func cameraLaunchAction(_ sender: Any){
if UIImagePickerController.isSourceTypeAvailable(.camera){
print("Cameera can be used.")
let ipc = UIImagePickerController()
ipc.sourceType = .camera
ipc.delegate = self
present(ipc, animated:true, completion: nil)
}else{
print("Camera is not avaiable")
}
}
isSourceTypeAvailable カメラが使えるかどうか判定するための関数。引数には.camera
もし、カメラが使えるなら、UIImagePickerControllerのオブジェクトを作成して、カメラからデータを受け取る
let ipc = UIImagePickerController() 定数でUIImagePickerControllerのインスタンスをひとつ作成する
ipc.sourceType = .camera ipcのソースタイプは、.camera
ipc.delegate = self delegate、写真を撮った後どの関数を出すか指定する。ここではデータを自分自身とするため、self
present(ipc, animated:true, completion: nil) イメージピッカーを表示する関数(present)。animatedで、アニメーションをつけて徐々に表示する。completionは、表示し終わったあとになにか動作をするか指定する。今回はなにもしないので、nilとする。JavaやPHPなどではnullだが、Swiftの場合はnil。
以下が、実際の記述画面である。
ここまでで、カメラを起動してそのデータを受け渡すところまで記述したので、次は、写真を撮った後に呼ばれるdelegateを書いていく。
②①からデータを受け取って終了する処理
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
photoImage.image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
dismiss(animated: true, completion: nil)
}
これは、最初に配置した3つのUIパーツ(ImageViewとButton)とは関係ない動作なので、先ほどUIと関連づけたクラスの外に書く。
UIパーツを配置する際に、写真データを配置するImageViewをphotoImageと名前をつけていたので、それを使う。
photoImage.image = info[UIImagePickerController.InfoKey.originalImage]as? UIImage ここでは、フォトイメージのイメージ型データを呼び出して、infoとして取り扱う。ここにもしデータがあれば、UIImage型のデータとしてこのイメージを渡してあげる。
dismiss(animated: true, completion: nil) dismissという関数で画像を選択するダイアログを閉じる。
以下が実際の記述画面である。
これで、撮影もしくは写真選択が終わったときのアクションが設定された。
③SNSに投稿する処理
@IBAction func shereAction(_ sender: Any) {
if let sharedImage = photoImage.image {
let shaerdItems = [sharedImage]
let controller = UIActivityViewController(activityItems: shaerdItems, applicationActivities: nil)
controller.popoverPresentationController?.sourceView = view
present(controller, animated: true, completion: nil)
}
}
if let sharedImage = photoImage.image {} sharedImageという定数に、photoImageのオブジェクトからイメージデータの取得。画像があれば、次にの処理を行う。
let shaerdItems = [sharedImage] 定数shaerdItemsに、これからシェアをするデータを格納する入れ物の作成。[]で囲うことで配列として複数のデータを入れることができる。
let controller = UIActivityViewController(activityItems: shaerdItems, applicationActivities: nil) 投稿用のアクティビティを保存するための箱を作成。引数activityItemsには、先ほど宣言したshaerdItems。applicationActivities:はnilにしておく。
controller.popoverPresentationController?.sourceView = view コントローラーの種類は、popoverPresentationControllerにする。iPadでの表示に対する対策なのでiPhoneには関係ない。
present(controller, animated: true, completion: nil) シェア用のメニューを表示する。
以下が実際の記述画面である。
ここまでできたらコードの保存(command + s)をする。
補足:Xcodeでは、ビルド&実行したら、自動でコードが保存される。
4.実機で動作確認
実装時に出た2つのエラー
'UIImagePickerControllerOriginalImage' has been renamed to 'UIImagePickerController.InfoKey.originalImage'
Replace 'UIImagePickerControllerOriginalImage' with 'UIImagePickerController.InfoKey.originalImage'
Google翻訳を使って見てみると、なんだかUIImagePickerControllerOriginalImageはUIImagePickerController.InfoKey.originalImageに変わりました。書きかえますよ?いいですよね!みたいな内容だったため、赤いエラー文を開き、 fix を押すと自動で書きかわり、エラーが解消された。後で調べてみると、バージョンの違いによる記述の仕様変更だったみたい。
5.実機で動作確認②
以下エラー
Showing Recent IssuesThe operation couldn’t be completed. Unable to log in with account 'hogehoge@me.com'. The login details for account 'hogehoge@me.com' were rejected.
provisioning profileがうまくいってないみたい。
Xcode => Preference => Account でログインを求められたのでパスワードを入れたら解決した。
カメラ機能の確認はシミュレータではできなくて実機で実行したのだが、完全私物の実機の画面はのせられないので、シミュレータの画面を置いておく。
「カメラを起動」ボタンも「SNS投稿」ボタンも、シミュレータでは動作確認できないので、UIの確認だけになった。
次回は、Web APIを使ったアプリを作る。