Swiftで現在位置を取得して、Coredataに保存する処理をまとめます。

まずはコード。 ボタンがタップされたら、中央位置をCoredataに保存する処理

   /// - Parameter sender: 中央位置をget,datpersonに保存
    @IBAction func registerCenter(_ sender: Any) {

//map専用クラスのmsMapAgentを作ってある 下記参照
        if let point = msMapAgent.centerCoordinate {
            // DatPersonはCoreData 新規インスタンスを生成
            let datPerson = DatPerson.newFormalOne()

//生成したインスタンスのプロパティlatitude,longitudeに現在位置を詰め込む
            datPerson.latitude = point.latitude
            datPerson.longitude = point.longitude

//保存処理 ここが大切
            try? Contract.managedObjectContext.save()
        }
    }

if let はオプショナルバインディング 右辺の値があったら pointに値が入る。つまりmsMapAgent.centerCoordinateが値を取得できたら pointに座標が入る

centerCoordinateはこちら

 /// マップ中央の座標(lat,lng)
    var centerCoordinate: CLLocationCoordinate2D? {

//mkMapViewはStoryBoardに接続したMap
        get { return mkMapView.centerCoordinate }
    }

centerCoodinateはswiftの関数 中心地の座標を取得してくれる

 // centerCoordinate allows the coordinate of the region to be changed without changing the zoom level.
    open var centerCoordinate: CLLocationCoordinate2D

これで、現在位置の座標がpointに格納される

その後、Coredataに保存する

let datPerson = DatPerson.newFormalOne()で

CoreDataのDatPersonクラスのインスタンスを生成している

DatPersonクラスには、name,dateなどのプロパティがある。説明は省略。

    /// 1つの DatMeeting が割り当て済みで、date = fdate
    static func newFormalOne() -> DatPerson {
        let dat = newOneWithId()
        dat.fdate = NSDate() as Date
        dat.lastMeeting = dat.fdate
        dat.name = dat.defaultName
        let meeting = DatMeeting.newOneWithId(dat)
        meeting.date = dat.fdate
        return dat
    }

ポイントはここから。CoreDataの保存処理

try? Contract.managedObjectContext.save()

これが大切 managedObjectContextはたびたび利用するので、プロパティにしておく。AppDelegateのpersistentContainerを利用して、Coredataを利用する。

こちらの図がわかりやすい

参照元:http://やっとわかったSwift/CoreData入門 【part2:とりあえず実装編】

そしてviewContextがsaveするとCoredataを通してSQLite(iPhone内のDB)にデータが保存される。

   /// アプリが使用してる CoreData スタック
    static var persistentContainer: NSPersistentContainer {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        return appDelegate.persistentContainer
    }
    /// アプリが使用してる NamagedObjectContext
    static var managedObjectContext:NSManagedObjectContext {
        return persistentContainer.viewContext
    }

saveはCoredataの関数

//throwsがあるのでエラーハンドリングが行われる関数であることがわかる
open func save() throws

saveメソッドは、ドキュメントによると、

コンテキストの親ストアが永続ストアコーディネーターである場合、変更は外部ストアにコミットされます。 コンテキストの親ストアが別の管理対象オブジェクトコンテキストである場合、save()はその親ストア内の管理対象オブジェクトのみを更新します。 外部ストアに変更をコミットするには、親が永続ストアコーディネーターであるコンテキストまでのコンテキストチェーンに変更を保存する必要があります。

エラーが出る可能性がある処理は、エラーハンドリングのtryをつける

Swiftのエラーハンドリング

これは実は、Swiftがクールと言われている所以なのですが、swiftにはOptional型によるnull安全が提供されています。これがいいのです。

エラーを送出する関数を呼び出すのは、do-catch文のdo節の内側か、throws指定された関数の中だけ。

ここまではJavaと同様ですが、Swiftでは更に、エラーを送出する関数の呼び出しに対して、try演算子を指定します。

そのためどこで、エラーが発生する可能性があるのか、理解しやすい

let favoriteSnacks = [
    "Alice": "Chips",
    "Bob": "Licorice",
    "Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
    let snackName = favoriteSnacks[person] ?? "Candy Bar"

//vendメソッドがエラーの可能性があるので tryをつける
    try vendingMachine.vend(itemNamed: snackName)
}

上記のようにまず、エラーハンドリングの throwがあり、かつその内部でどの関数がエラーを吐く可能性があるかを明示的にtryをつけるので、可読性が良いし、書きやすい