連載
» 2015年04月07日 05時00分 公開

iPhone 6/6 Plusアプリ開発入門(5):Swiftのカスタムクラスの作り方――プロトコル、サブクラス、イニシャライザー、タイププロパティメソッドのオーバーライド、デリゲートについて注釈の作成で学ぶ (4/4)

[平屋真吾,クラスメソッド株式会社]
前のページへ 1|2|3|4       

作成したカスタムオブジェクト/ビューを使う

 カスタム注釈オブジェクト「PhotoAnnotation」とカスタム注釈ビュー「PhotoAnnotationView」の実装が完了しました。これらのオブジェクトを使用して注釈を地図上に表示するためにViewControllerを修正していきます。

デリゲート(delegate)の設定

 ViewControllerの修正のメインの作業は、「mapView:viewForAnnotation:メソッドを追加し、注釈ビューのセットアップと更新処理を記述する」ことですが、そのためにはViewControllerがMapViewの「デリゲートオブジェクト」になる必要があります。

 「デリゲート(移譲)」について、アップル公式のドキュメント「Objective-C プログラミングの概念」では以下のように説明されています。

デリゲート(delegate、委譲)とは、あるオブジェクトがプログラム中でイベントに遭遇したとき、それに代わって、または連携して処理するオブジェクトのことです。

 ViewControllerがMapViewのデリゲートオブジェクトとなることで、「注釈ビューのセットアップ/更新」などの処理をViewControllerに任せることができます。

 必要な作業は二つあります。

 一つ目はMKMapViewDelegateプロトコルを採用することです。PhotoAnnotationの実装したときと同様にクラス名の後に採用したいプロトコル名を追加します。

...
class ViewController: UIViewController, MKMapViewDelegate {  // MKMapViewDelegateを追加
...
}
修正後のViewController.swiftファイルの先頭部分

 二つ目に必要なことはMKMapViewの「delegate」プロパティに「self」(ViewController自身)をセットすることです。selfをセットする1行をprepareMapViewメソッドに追加します(下記コードの4行目)。

private func prepareMapView() {
    self.mapView.rotateEnabled = false
    self.mapView.pitchEnabled = false
    self.mapView.delegate = self  // 追加
    
    let centerCoordinate = CLLocationCoordinate2D(latitude: 35.681382, longitude: 139.766084)
    let initialSpan = MKCoordinateSpan(latitudeDelta: 0.4, longitudeDelta: 0.4)
    let initialRegion = MKCoordinateRegion(center: centerCoordinate, span: initialSpan)
    self.mapView.setRegion(initialRegion, animated: true)
}
修正後のprepareMapViewメソッド

注釈オブジェクト作成部分を修正

 prepareAnnotationsメソッドを以下のように修正します。PhotoAnnotationを作成してMapViewに追加するように修正しています。

private func prepareAnnotations() {
    let fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: nil)
    fetchResult?.enumerateObjectsUsingBlock ({result, index, stop in
        
        if let asset = result as? PHAsset {
            if asset.location != nil {
                let annotation = PhotoAnnotation(asset: asset)
                self.mapView.addAnnotation(annotation)
            }
        }
    })
}

メイン作業――mapView:viewForAnnotation:メソッドを追加する

 さて、いよいよ先の「今回の大まかな流れ」の2.と3.にあった「mapView:viewForAnnotation:」メソッドの追加です。mapView:viewForAnnotation:メソッドは注釈ビューが必要になったタイミングで呼ばれます。このメソッド内で行う主要な処理は以下の通りです。

  1. MKAnnotationViewの取得または作成(2〜8行目)
  2. PHImageManagerを使用して写真の実データを取得する(10〜28行目)
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
    let photoAnnotation = annotation as? PhotoAnnotation
    let photoAnnotationViewID = "photoAnnotationView"
    var photoAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(photoAnnotationViewID) as? PhotoAnnotationView
    
    if photoAnnotationView == nil {
        photoAnnotationView = PhotoAnnotationView(annotation: photoAnnotation, reuseIdentifier: photoAnnotationViewID)
    }
    
    if let image = photoAnnotation?.image {
        photoAnnotationView?.image = image
    } else {
        let screenScale = UIScreen.mainScreen().scale
        let targetSize = CGSize(
            width: PhotoAnnotationView.size.width * screenScale,
            height: PhotoAnnotationView.size.height * screenScale)
        
        PHImageManager().requestImageForAsset(
            photoAnnotation?.asset,
            targetSize: targetSize,
            contentMode: .AspectFill,
            options: nil,
            resultHandler: {(image, info) -> Void in
                photoAnnotation?.image = image;
                photoAnnotationView?.thumbnailImage = image;
            }
        )
    }
    
    return photoAnnotationView
}
  • MKAnnotationViewの取得または作成(2〜8行目)

 4行目でMapViewのdequeueReusableAnnotationViewWithIdentifierメソッドを使用して未使用の注釈ビューの取得を試みています。

 未使用の注釈ビューがなかった場合の処理は6〜8行目です。PhotoAnnotationViewに実装したイニシャライザーを使用して初期化を行っています。

  • PHImageManagerを使用して写真の実データを取得する(10〜28行目)

 photoAnnotationオブジェクトのimageプロパティがnilでなければphotoAnnotationViewのimageプロパティにセットします。

 nilであれば、PHImageManagerのrequestImageForAssetメソッドを使用して写真の実データをリクエストし、引数のクロージャ内で、得られた画像データをphotoAnnotationとphotoAnnotationViewのプロパティにセットしています。

 13〜16行目では、リクエストする画像データのサイズを作成しています。ポイント単位の大きさでそのままリクエストすると十分な大きさの画像が得られなかったので、PhotoAnnotationViewのsizeプロパティの値(44×44)に物理的なスクリーンのscaleを掛けたサイズ(iPhone 6やiPhone 5sなどであれば88×88、iPhone 6 Plusであれば132×132)のCGSizeを作成しています。

動作確認

 [Run]ボタンをクリックしてiOSシミュレーターで動かしてみましょう。カスタムの注釈ビューが表示されます。

図9 iOSシミュレーター(iPhone 6)の実行結果

 注釈ビューをタップすると、吹き出しが表示されます。

図10 iOSシミュレーター(iPhone 6)の実行結果(注釈ビュータップ後)

次回でPhotoMapアプリが完成

 今回はカスタムの注釈オブジェクトと注釈ビューを新規作成し、地図上に写真のサムネイルが表示されるように修正しました。

 次回は、注釈ビューが選択状態の場合に表示される吹き出しをタップした際の動きと、その時に表示される画面を作成します。次回でPhotoMapアプリが完成する予定です。

著者紹介

平屋真吾

クラスメソッド株式会社 iPhoneアプリサービス事業部所属のプログラマーです。iOSアプリの開発がメインですが、デザインやAWSなども勉強中です。

ブログ:http://dev.classmethod.jp/author/hiraya-shingo/


前のページへ 1|2|3|4       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。