【Xcode7.0】【swift2.0】環境準備〜実機でカメラを起動して写真撮影

最近(2年程度)がっつりエンジニアリングから遠ざかっていたので、勉強がてらiOSアプリを作成しようと思った。まずは慣れるために以下のようなシンプルなアプリをつくる。 今回のXcode7.0でお金を払ってデベロッパー登録しなくても、アプリが実機テストできるようになったようなので、beta版のXcode7.0を利用する。

要件

*アプリを起動するとカメラの起動。アプリ起動時にタップをすると撮影し、写真に保存

動作環境

手順

  1. Xcode7.0(beta 5)のダウンロード&インストール
  2. プロジェクトの作成
  3. ViewControllerに処理を追加
  4. 実機へのビルド
  5. 動作確認

Xcode7.0のダウンロード&インストール

Xcodeの公式サイトからダウンロードできる。画面にしたがってすすめていく。Xcode6系を利用していても別のアプリケーションとしてインストールされるので恐れずインストール。勝手にSwift2.0もインストールされる。 Xcode - ダウンロード - Apple Developer

プロジェクトの作成

「Shift+Command+N」で新規プロジェクトを作成。「Single View Application」を選択。適当にProduct Nameなどを設定。テストなどは今回行わない。

f:id:simpleplay:20150829140255p:plain

プロジェクト作成後の画面で、ビルドする端末の情報を記載する。

今回はiOS8.4.1の端末にビルドして動作確認するので、Deployment Targetをそのように設定。

f:id:simpleplay:20150829140247p:plain

ViewControllerに処理を追加

どうやって動かすかも分からないので、参考にするサイトの通りにViewController.swiftを編集。

002 カメラの起動と画像の保存 - Swift Docs

コピペしてビルドしてみると、以下のエラーが発生するので地道に調べながらデバッグ

Extra argument 'error' in call

AVCaptureDeviceInput Class Reference

今回のバージョンでswiftの返り値が変更されており、errorの返り値ではなく、例外が起こればthrowsを返すことになっている。エラーが起こっている箇所を以下のようにして、とりあえず動くようにする。

'layerWithSession' is unavailable: use object construction 'AVCaptureVideoPreviewLayer(session:)'

→ layerWithSessionsというメソッドがなくなっている。同ページにあるinitWithSessionsで代替 AVCaptureVideoPreviewLayer Class Reference

以下のコードでビルドできるようになるところまで確認。 シミュレータだと、カメラがわからないから強制終了されるので、実機にビルドして確認。

//
//  ViewController.swift
//  AVFoundation002
//

import UIKit
import AVFoundation

class ViewController: UIViewController {
    // セッション.
    var mySession : AVCaptureSession!
    // デバイス.
    var myDevice : AVCaptureDevice!
    // 画像のアウトプット.
    var myImageOutput : AVCaptureStillImageOutput!
    
    override func viewDidLoad() {
        super.viewDidLoad()        
        // セッションの作成.
        mySession = AVCaptureSession()
        // デバイス一覧の取得.
        let devices = AVCaptureDevice.devices()
        
        // バックカメラをmyDeviceに格納.
        for device in devices{
            if(device.position == AVCaptureDevicePosition.Back){
                myDevice = device as! AVCaptureDevice
            }
        }
        
        // バックカメラからVideoInputを取得.
        let videoInput: AVCaptureInput!
        do {
            videoInput = try AVCaptureDeviceInput.init(device: myDevice!)
        }catch{
            videoInput = nil
        }
        
        // セッションに追加.
        mySession.addInput(videoInput)
        // 出力先を生成.
        myImageOutput = AVCaptureStillImageOutput()
        // セッションに追加.
        mySession.addOutput(myImageOutput)
        
        // 画像を表示するレイヤーを生成.
        let myVideoLayer : AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session:mySession)
        myVideoLayer.frame = self.view.bounds
        myVideoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        
        // Viewに追加.
        self.view.layer.addSublayer(myVideoLayer)
        
        // セッション開始.
        mySession.startRunning()
        
        // UIボタンを作成.
        let myButton = UIButton(frame: CGRectMake(0,0,120,50))
        myButton.backgroundColor = UIColor.redColor();
        myButton.layer.masksToBounds = true
        myButton.setTitle("撮影", forState: .Normal)
        myButton.layer.cornerRadius = 20.0
        myButton.layer.position = CGPoint(x: self.view.bounds.width/2, y:self.view.bounds.height-50)
        myButton.addTarget(self, action: "onClickMyButton:", forControlEvents: .TouchUpInside)
        
        // UIボタンをViewに追加.
        self.view.addSubview(myButton);
    }
    
    // ボタンイベント.
    func onClickMyButton(sender: UIButton){
        // ビデオ出力に接続.
        let myVideoConnection = myImageOutput.connectionWithMediaType(AVMediaTypeVideo)
        
        // 接続から画像を取得.
        self.myImageOutput.captureStillImageAsynchronouslyFromConnection(myVideoConnection, completionHandler: { (imageDataBuffer, error) -> Void in
            
            // 取得したImageのDataBufferをJpegに変換.
            let myImageData : NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataBuffer)
            
            // JpegからUIIMageを作成.
            let myImage : UIImage = UIImage(data: myImageData)!
            
            // アルバムに追加.
            UIImageWriteToSavedPhotosAlbum(myImage, self, nil, nil)
        })  
    }    
}

実機へのビルド

Macbook airiPadをケーブルでつなぐと、Xcode画面のビルド先で、実際の端末を選択できるようになる。 ビルド先を選択してビルド。(Command + R)

動作の確認

とりあえず動作を確認できるところまではきた。

雑感

すぐに動くものが作れて楽しい。swiftもおもちゃみたいにコードが書けるので楽しそう。 これから開発を進めていくにしても、appleはドキュメントが充実しているので、特に本を買う必要はなさそうというのが印象。