20200301のiOSに関する記事は9件です。

iOSアプリ開発 デザインパターン入門を読んで

目次

第1章 前準備 ~おすすめ書籍
第2章 前準備 ~オブジェクト指向とは
第3章 前準備 ~プロトコル指向とは
第4章 前準備 ~入門書には書かれていないが重要なiOS開発Tips
第5章 Model View Controllerデザインパターン
第6章 MVCでタスク管理アプリを作ろう
第7章 Model View ViewModelデザインパターン
第8章 MVVMでGitHubクライアントアプリを作ってみよう

第1章 前準備 ~おすすめ書籍

学習者のレベル別で技術書を紹介している。

第2章 前準備 ~オブジェクト指向とは

オブジェクト指向、継承の概念を図を使って解説していて、初心者の方には分かりやすいだろうなぁと思いました。
継承のメリット、デメリットに関しても説明されており、再確認できてよかったです。

第3章 前準備 ~プロトコル指向とは

オブジェクト志向のデメリットを何がデメリットかをはっきりさせて解説した上で、そのデメリットをプロトコル志向がどう解決したか解説されていて、理解しやすかったです。

第4章 前準備 ~入門書には書かれていないが重要なiOS開発Tips

コードでレイアウト、IBActionを使わずコードで定義、ライフサイクル、メモリ管理、Delegate、Closure、Grand Central Dispatch、WebAPIといった、実際の現場で「あれ?これどうやったかな?」となるようなTipsについて簡潔に書かれていて、効率的に再確認できました。

第5章 Model View Controllerデザインパターン

MVCのModel、Controller、Viewのそれぞれの役割を2ページで簡潔に図を使って説明されていて、再確認しやすかったです。

第6章 MVCでタスク管理アプリを作ろう

サンプルコードをダウンロードしてみてXcodeで見てみようと思います。

第7章 Model View ViewModelデザインパターン

MVVMのModel、ViewController、View、ViewModelのそれぞれの役割を2ページで簡潔に図を使って説明されていて、再確認しやすかったです。

第8章 MVVMでGitHubクライアントアプリを作ってみよう

第6章と同様です。

全体を通して

身近な乗り物などを例に図を使って解説されていて分かりやすかったです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUIで作るドラえもん【顔編】

はじめに

日曜日で暇なので, SwiftUIを使ってドラえもんを作ってみました.

この記事で完成するドラえもんは以下の画像です.
口を開けているドラえもんは難しそうなので断念しました.
かなり本物に近くないですか?笑

DoraFace

さぁ作って行きましょう.

土台づくり

まず,以下の画像のような土台となる青の円とその中にある円から作って行きましょう.
ドラえもんって意識してませんでしたが,地味に楕円なんだと感じました.
確かによくよく見たら楕円なんですよね.

土台の色のみ,Asset Catalogで色を管理しています.
(鼻も管理した方が良さそう...)

土台

以下コードです.

ContentView.swift
struct base: View {
    var body: some View {
        ZStack {
            // 土台
            Ellipse()
            .overlay(
              Ellipse()
             .stroke(Color.black,lineWidth: 2)
            )
            .frame(width: 300, height: 290)
            .foregroundColor(Color("DoraColor"))

            // 顔
            Ellipse()
                .frame(width: 270 , height: 250)
                .foregroundColor(Color.white)
                .overlay(
                  Ellipse()
                 .stroke(Color.black,lineWidth: 2)
                )
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 100 } )
        }
    }
}

次に目です.

eyeeye

ContentView.swift
struct eyes: View {
    var body: some View {
        HStack(spacing:0) {
            // 左目
            ZStack {
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)

                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -5 })

            }

            ZStack {
                // 右目
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )

                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)

                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 25 } )
            }
        }
    }
}

続いては鼻ですね.

nosenose

ContentView.swift
struct nose: View {
    var body: some View {
        Group {
            // 鼻
            ZStack{
                Circle()
                    .frame(width: 50, height: 50)
                    .foregroundColor(Color.red)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                Circle()
                    .frame(width: 20, height: 10)
                    .foregroundColor(Color.white)
                    .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 20})
                    .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 15})
            }
            .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 60 } )

            // 人中?
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 110, height: 2)
                .rotationEffect(Angle(degrees: 90))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -45 } )
        }
    }
}

ここまでくるとそれっぽくなってきました.

CatBeardCatBeard

ContentView.swift
struct CatBeard: View {
    var body: some View {
        Group {
            // 左髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )

            // 右髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
        }
    }
}

最後に口です.

mouthmouth

ContentView.swift
struct Mouth: View {
    var body: some View {
        Circle()
            .trim(from: 0.05, to: 0.45)
            .stroke(Color.black,lineWidth: 3)
            .frame(width: 200, height: 200)
    }
}

完成

無理やりですがなんとか完成しました.
DoraFace

全文
ContentView.swift
import SwiftUI

struct base: View {
    var body: some View {
        ZStack {
            // 土台
            Ellipse()
            .overlay(
              Ellipse()
             .stroke(Color.black,lineWidth: 2)
            )
            .frame(width: 300, height: 290)
            .foregroundColor(Color("DoraColor"))

            // 顔
            Ellipse()
                .frame(width: 270 , height: 250)
                .foregroundColor(Color.white)
                .overlay(
                  Ellipse()
                 .stroke(Color.black,lineWidth: 2)
                )
                .alignmentGuide(.leading, computeValue: { _ in 10 } )
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 100 } )
        }
    }
}

struct eyes: View {
    var body: some View {
        HStack(spacing:0) {
            // 左目
            ZStack {
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)

                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -5 })

            }

            ZStack {
                // 右目
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )

                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)

                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 25 } )
            }
        }
    }
}

struct nose: View {
    var body: some View {
        Group {
            // 鼻
            ZStack{
                Circle()
                    .frame(width: 50, height: 50)
                    .foregroundColor(Color.red)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                Circle()
                    .frame(width: 20, height: 10)
                    .foregroundColor(Color.white)
                    .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 20})
                    .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 15})
            }
            .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 60 } )
            // 人中?
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 110, height: 2)
                .rotationEffect(Angle(degrees: 90))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -45 } )
        }
    }
}

struct CatBeard: View {
    var body: some View {
        Group {
            // 左髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )

            // 右髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )

            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
        }
    }
}

struct Mouth: View {
    var body: some View {
        Circle()
            .trim(from: 0.05, to: 0.45)
            .stroke(Color.black,lineWidth: 3)
            .frame(width: 200, height: 200)
    }
}

struct DoraFace: View {
    var body: some View {
        ZStack{
            // 土台
            base()
            // 目
            eyes()
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 130})
            // 鼻
            nose()
            // 髭
            CatBeard()
            // 口
            Mouth()
        }
    }
}

struct ContentView: View {
    var body: some View {
        VStack{
            Text("ドラえもん")
                .font(.largeTitle)
            DoraFace()
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

終わりに

あまり綺麗ではありませんが,なんとか完成させることができました.
次の暇な日曜日にでも綺麗なコードに修正していこうと思います.

ちなみに,今回のタイトルに,【顔編】とありますが,【体編】を作る予定はありません.笑

SwiftUI初心者なのでもっと良い書き方があればご教示ください.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Xcode]ディレクトリをターミナル にドラッグ&ドロップすれば絶対パスが表示される

Project Navigatorのgroupからターミナル にドラッグ&ドロップすればgroupまでの絶対パスが表示されます。

スクリーンショット_2020-03-01_11_15_51.png

こういう時に便利

  • Xcodeを開いていてさくっとルートディレクトリにファイルを作りたいとき。
    • PodfileCartfileなど

このままではルートディレクトリでは無いので先頭のパスを消す必要があります。

$ cd /Users/[UserName]/iOS/[Project Name]/[Project Name]⬅︎先頭のパスが不要
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Maps iOS Utils で Marker をまとめて表示する

Google Maps SDK を使用していてマップ上にマーカーを立てることはよくあると思います
ただ、マップ上にマーカーを建てすぎると、広域表示にした際にマーカーが密集しちゃって見辛くなってしまうってこともよくあると思います

そんな時マーカーを1つにまとめたいなーと思ったので、その実装方法を残しておきたいと追います

GrWyuKwR.gif

開発環境

Xcode:11.1(11A1027)
Swift 5
iOS:13.1
CocoaPods: 1.8.0

実装

ライブラリのインストール

Google Maps iOS Utils をインストールするために CocoaPods を使用します
以下のように Podfile を編集し、 pod install を実行してください

target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
  use_frameworks!

  pod 'GoogleMaps'
  pod 'Google-Maps-iOS-Utils'
end

こちらのセットアップガイドにも記載されていますが、
CocoaPods のバージョンが 1.8.1 以上はサポート対象外のようです

1.6.1 が推奨されているようですが、Xcode11 では 1.6.1 を使用した場合にビルドが通らなかったため、今回は 1.8.0 を使用しています

CocoaPods のバージョンを下げるにはこちらを参考にしてください

マーカーをまとめて表示する用の class を作成

普段は GMSMarker class を使用してマーカーを表示していますが、
マーカーをまとめて表示するには GMUClusterItem protocol に準拠した class を作成し、その class を使用してマーカーを表示する必要があります

import GoogleMapsUtils

class POIItem: NSObject, GMUClusterItem {

    var position: CLLocationCoordinate2D

    init(position: CLLocationCoordinate2D) {
        self.position = position
    }
}

Map 上にマーカーを配置

先ほど作成した独自 class POIItem を使用してマーカーを Google Map 上に表示していきます

import UIKit
import GoogleMaps
import GoogleMapsUtils

class ViewController: UIViewController {

  // デフォルトの位置情報(仮で東京駅付近にしています)
    let defaultPositionLat = 35.681223
    let defaultPositionLng = 139.767059
    private var mapView: GMSMapView!
    /// Map 上に表示するマーカーを管理するためのプロパティ
    private var clusterManager: GMUClusterManager!

    override func viewDidLoad() {
        super.viewDidLoad()

        // GoogleMapの初期位置
        let camera = GMSCameraPosition.camera(withLatitude: defaultPositionLat, longitude: defaultPositionLng, zoom: 17.0)
        mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
        view = mapView

        let iconGenerator = GMUDefaultClusterIconGenerator()
        let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
        let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
        clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)

        // マーカーをランダムに生成して Map 上に表示
        generateClusterItems()
    }

    private func generateClusterItems() {
        let extent = 0.01
        for _ in 1...100 {
            let lat = defaultPositionLat + extent * randomScale()
            let lng = defaultPositionLng + extent * randomScale()
            let item = POIItem(position: CLLocationCoordinate2DMake(lat, lng))
            clusterManager.add(item)
        }
        // Map にマーカーを描画
        clusterManager.cluster()
    }

    /// ランダムな位置にマーカーを表示するための乱数を生成
    private func randomScale() -> Double {
        return Double(arc4random()) / Double(UINT32_MAX) * 2.0 - 1.0
    }
}

上記のコードを実行すると、最初に載せた gif のような挙動になるかと思います

Delegate とか

マーカーをタップした際のアクションを設定したい場合、以下のように GMUClusterManagerDelegateGMSMapViewDelegate を設定してあげるとタップ時のアクションが設定可能な脳です

class ViewController: UIViewController, GMUClusterManagerDelegate, GMSMapViewDelegate {

    private var mapView: GMSMapView!
    private var clusterManager: GMUClusterManager!

    override func viewDidLoad() {
        super.viewDidLoad()

        // ... Rest of code omitted for easy reading.

        // Register self to listen to both GMUClusterManagerDelegate and
        // GMSMapViewDelegate events.
        clusterManager.setDelegate(self, mapDelegate: self)
    }

    // MARK: - GMUClusterManagerDelegate
    func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
        let newCamera = GMSCameraPosition.cameraWithTarget(cluster.position,
      zoom: mapView.camera.zoom + 1)
        let update = GMSCameraUpdate.setCamera(newCamera)
        mapView.moveCamera(update)
    }

    // MARK: - GMUMapViewDelegate
    func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
        if let poiItem = marker.userData as? POIItem {
            NSLog("Did tap marker for cluster item \(poiItem.name)")
        } else {
            NSLog("Did tap a normal marker")
        }
        return false
    }
}

終わりに

Google Maps iOS Utils というライブラリはマーカーをまとめるだけでなく、
マーカーの画像をカスタマイズしたり KML や GeoJSON をレンダリングできたりと他にも色々な機能が使用できるようなので、機会があれば触ってみようかと思います

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Maps iOS Utils でマーカーをまとめて表示する

Google Maps SDK を使用していてマップ上にマーカーを立てることはよくあると思います
ただ、マップ上にマーカーをたてすぎると、広域表示にした際にマーカーが密集しちゃって見辛くなってしまうってこともよくあると思います

そんな時マーカーを1つにまとめたいなーと思ったので、その実装方法を残しておきたいと追います

GrWyuKwR.gif

開発環境

Xcode:11.1(11A1027)
Swift 5
iOS:13.1
CocoaPods: 1.8.0

実装

ライブラリのインストール

Google Maps iOS Utils をインストールするために CocoaPods を使用します
以下のように Podfile を編集し、 pod install を実行してください

target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
  use_frameworks!

  pod 'GoogleMaps'
  pod 'Google-Maps-iOS-Utils'
end

こちらのセットアップガイドにも記載されていますが、
CocoaPods のバージョンが 1.8.1 以上はサポート対象外のようです

1.6.1 が推奨されているようですが、Xcode11 では 1.6.1 を使用した場合にビルドが通らなかったため、今回は 1.8.0 を使用しています

CocoaPods のバージョンを下げるにはこちらを参考にしてください

マーカーをまとめて表示する用の class を作成

普段は GMSMarker class を使用してマーカーを表示していますが、
マーカーをまとめて表示するには GMUClusterItem protocol に準拠した class を作成し、その class を使用してマーカーを表示する必要があります

import GoogleMapsUtils

class POIItem: NSObject, GMUClusterItem {

    var position: CLLocationCoordinate2D

    init(position: CLLocationCoordinate2D) {
        self.position = position
    }
}

Map 上にマーカーを配置

先ほど作成した独自 class POIItem を使用してマーカーを Google Map 上に表示していきます

import UIKit
import GoogleMaps
import GoogleMapsUtils

class ViewController: UIViewController {

  // デフォルトの位置情報(仮で東京駅付近にしています)
    let defaultPositionLat = 35.681223
    let defaultPositionLng = 139.767059
    private var mapView: GMSMapView!
    /// Map 上に表示するマーカーを管理するためのプロパティ
    private var clusterManager: GMUClusterManager!

    override func viewDidLoad() {
        super.viewDidLoad()

        // GoogleMapの初期位置
        let camera = GMSCameraPosition.camera(withLatitude: defaultPositionLat, longitude: defaultPositionLng, zoom: 17.0)
        mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
        view = mapView

        let iconGenerator = GMUDefaultClusterIconGenerator()
        let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
        let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
        clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)

        // マーカーをランダムに生成して Map 上に表示
        generateClusterItems()
    }

    private func generateClusterItems() {
        let extent = 0.01
        for _ in 1...100 {
            let lat = defaultPositionLat + extent * randomScale()
            let lng = defaultPositionLng + extent * randomScale()
            let item = POIItem(position: CLLocationCoordinate2DMake(lat, lng))
            clusterManager.add(item)
        }
        // Map にマーカーを描画
        clusterManager.cluster()
    }

    /// ランダムな位置にマーカーを表示するための乱数を生成
    private func randomScale() -> Double {
        return Double(arc4random()) / Double(UINT32_MAX) * 2.0 - 1.0
    }
}

上記のコードを実行すると、最初に載せた gif のような挙動になるかと思います

Delegate とか

マーカーをタップした際のアクションを設定したい場合、以下のように GMUClusterManagerDelegateGMSMapViewDelegate を設定してあげるとタップ時のアクションが設定可能なようです

class ViewController: UIViewController, GMUClusterManagerDelegate, GMSMapViewDelegate {

    private var mapView: GMSMapView!
    private var clusterManager: GMUClusterManager!

    override func viewDidLoad() {
        super.viewDidLoad()

        // ... Rest of code omitted for easy reading.

        // Register self to listen to both GMUClusterManagerDelegate and
        // GMSMapViewDelegate events.
        clusterManager.setDelegate(self, mapDelegate: self)
    }

    // MARK: - GMUClusterManagerDelegate
    func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
        let newCamera = GMSCameraPosition.cameraWithTarget(cluster.position,
      zoom: mapView.camera.zoom + 1)
        let update = GMSCameraUpdate.setCamera(newCamera)
        mapView.moveCamera(update)
    }

    // MARK: - GMUMapViewDelegate
    func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
        if let poiItem = marker.userData as? POIItem {
            NSLog("Did tap marker for cluster item \(poiItem.name)")
        } else {
            NSLog("Did tap a normal marker")
        }
        return false
    }
}

終わりに

Google Maps iOS Utils というライブラリはマーカーをまとめるだけでなく、
マーカーの画像をカスタマイズしたり KML や GeoJSON をレンダリングできたりと他にも色々な機能が使用できるようなので、機会があれば触ってみようかと思います

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Debug areaにerror: module importing failed: Missing parentheses in call to 'print'. Did you mean print('Whoops! You are missing the <' + arg.argName + "> argument.')? (fbildb.py, line 98), File "temp.py", line 1, in <module>と表示されるとき。

Debug areaにいつのまに次のエラーが表示されるようになった。
スクリーンショット 2020-03-01 1.16.34.png

環境

Xcode11.1
Swift5.0
chisel 1.8.1

結論

上記のエラーはchiselを利用していたため、起きたものでした。
Xcode11ではエラーがあるとissueがあがってました。

v2.0.0では解決されているとのことでした。
Homebrewでchiselを入れていたので、
$ brew upgrade chisel
でバージョンを1.8.1 => 2.0.0に変更したら、エラー文が表示されなくなりました。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CustomCellに値を代入したときにFatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: custom cell: file xxxというエラーが出た

nibで作成したCustom cellに値を入れようとした時に次のエラーが出ました。

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: custom cell: file xxx

結論

  • tableViewのregisterメソッドが間違っていた。
before
tableView.register(UserSearchCell.self, forCellReuseIdentifier: UserSearchCell.className)
after
tableView.register(UINib(nibName: UserSearchCell.className, bundle: nil), forCellReuseIdentifier: UserSearchCell.className)

cellをコードで実装している時はbeforeが正しくて、cellをnibで作成した時はafterでテーブルセルの作成に使用するクラスを登録しないといけないかと思われます。

参考

register(_:forCellReuseIdentifier:) - UITableView | Apple Developer Documentation

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "xxx" nib but the view outlet was not set.'というエラーがでたとき。

概要

イニシャライザでnibを呼び出す時に次のようなエラーが出た。

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "xxxViewController" nib but the view outlet was not set.'
init()
init() {
        super.init(nibName: UserSearchViewController.className, bundle: nil)
    }

loadViewで呼び出した時はこのエラーがでなかった。

loadView()
override func loadView() {
        guard let view = UINib(nibName: "UserSearchViewController", bundle: nil).instantiate(withOwner: self, options: nil).first as? UIView else { return }
        self.view = view
    }

結論

貼り付けた画像_2020_03_01_13_57.png

  • ①InspectorのFile`sOwnerにCustomClassをセットする。
  • ②Placeholders>File`s OwnerからViewにOutletで接続する。(※画像を参考)

これでエラーがでなくなりました。

コードで実装していたときは、Ownerを指定したのに、init()の時はnibをロードするだけでOwnerを指定していたなかったのが原因かと思われます。

参考

https://qiita.com/maru_u/items/9b2f7dc0c4f5f3f5cac8

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Library not loaded: @rpath/Flutter.framework/Flutter

  • 内容:
    Flutterでアプリを作成し、実機で確認をしようとした際に、 下記のエラーが発生したため、実機での確認ができませんでしたので、 情報共有させていただきます。
    ※情報の判断はご自身の責任でお願い致します。

dyld: Library not loaded: @rpath/Flutter.framework/Flutter

  • 環境:
    Xcode 11.3
    iPhoneX(iOS13.3.1)
    iPhone5S(iOS10.3.2)

  • 結果:
    本家サイトに追記がありました。特定の条件の場合、エラーが出てしまうようです。

    • signing identity profile
    • iOS13.3.1
      ですと、ダメなようです。

iPhone5S(iOS10.3.2)では、実機で実行されることを確認致しました。

以上となります。?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む