解放区在住氷翠 緑の閃光
【解放区在住氷翠】氷翠のお気楽日記

データベースを思い出した。

2018-05-06

どうも、氷翠です。

なんか、ぼーっとしていたら、ふと仕事で使うmacのアプリケーションのことを考えてしまっていた。
で、そんな中で思い出したことがあった。

「データベース…」

そう、氷翠は元々データベースを使ったアプリケーションを作るのが得意だった。
初めて使うプログラム言語だったからその発想に至らなかったのだ。

現在、そのアプリケーションのデータのあり方についていろいろと調べたり研究していたりしていたのだが、元々データベースがあるアプリケーションを得意としているのだから、はじめからそのデータベースを利用したものを考えたらよかったのだ。

その時だけのデータだとしても大量のデータをあつかうのだから、データベースを組み込んだらいいじゃない。

ということで、調べてみた。

今回のUIはこちら

完成していますよ。
実験は成功なんです。

じゃ、とりあえず、作成してみましょうか。

ここでいきなり問題です。
プロジェクトを作成する段階で下の方にある「Use Core Data」のところにチェックを入れておく必要があります。
これを知らなかったら駄目w

プロジェクトの中身はこんな感じで。
まずはStoryboardの内容は最初のものを形として作っておきます。

出力は今回はコンソールに出力しようと思うので、そのためのviewは必要はありません。

で、次に「testDB.xcdatamodeld」というファイルにアクセスします。
これはデータベースの形をどんなものにするのか、データベースのフィールド作成といったところでしょうか。

「ENTITIES」という項目のところに追加します。
画面の下の方に「+」のボタンがあるので、これで追加ができます。
で、この左側に「Entity」という名前のものができます。氷翠はここで引っかかっていたようでした。その詳細は後ほど。
そして、右側の部分でフィールドを用意します。
今回は「id」というフィールドにINT16、「name」というフィールドにStringの型を用意しました。

ここからプログラムに入ります。

「AppDelegate.swift」ファイルはなにやらたくさん記述されているようですが、今回はこれは放置します。

上記にあるファイルの一覧の下の方に、「db.swift」というファイルがあるのがわかります。
データベースの構成を示したものだとおもってください。

import Foundation
import CoreData

@objc(testDB)
class testDB: NSManagedObject {
	
	@NSManaged var id: Int16
	@NSManaged var name: String
}

中身はこれだけ。
問題は「import CoreDatga」という表記がある。ということと、「@objc(testDB)」という部分。まぁ、これはおまじない。
その内容は、「NSManagedObject」というCoreDataの中で定義されている型になるようです。
で、プロパティとして、「@NSManaged」というものでフィールドを定義しています。
これは「testDB.xcdatamodeld」で定義したものをここでもう一度プログラムの中で使うために用意します。
このファイルは以上。

問題は「ViewController.swift」のファイルです。

import Cocoa

class ViewController: NSViewController {

	@IBOutlet weak var IDnumber: NSTextField!
	@IBOutlet weak var nameField: NSTextField!
	
	// IDと名前を入れる配列を用意
	var id: [Int16] = []
	var name: [String] = []
	
	override func viewDidLoad() {
		super.viewDidLoad()
	}

	override var representedObject: Any? {
		didSet {
		// Update the view, if already loaded.
		}
	}

	// 書き込み処理
	@IBAction func writeData(_ b: NSButton) {
		let appDel = NSApplication.shared.delegate as! AppDelegate
		let context = appDel.persistentContainer.viewContext
		let entity = NSEntityDescription.entity(forEntityName: "Entity", in: context)
		let newData = NSManagedObject(entity: entity!, insertInto: context)
		newData.setValue(Int16(IDnumber.stringValue), forKey: "id")
		newData.setValue(nameField.stringValue, forKey: "name")
		do {
			try context.save()
		} catch {
			print("Failed saving")
		}
	}
	
	// 読み込み処理
	@IBAction func readData(_ b: NSButton) {
		let appDel = NSApplication.shared.delegate as! AppDelegate
		let context = appDel.persistentContainer.viewContext
		let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Entity")
		//request.predicate = NSPredicate(format: "age = %@", "12")
		request.returnsObjectsAsFaults = false
		do {
			let result = try context.fetch(request)
			for data in result as! [NSManagedObject] {
				let read_id = String(data.value(forKey: "id") as! Int16)
				let read_name = data.value(forKey: "name") as! String
				print(String(read_id)+" // "+read_name)
			}
			
		} catch {
			
			print("Failed")
		}
		
	}
}

まずはこちらは全文ですが、少しづつやっていきます。

@IBOutlet weak var IDnumber: NSTextField!
@IBOutlet weak var nameField: NSTextField!

いつもどおり、Storyboardでつないでおいてください。

var id: [Int16] = []
var name: [String] = []

とりあえず、この中で使えるようにするため、配列変数として用意しておきます。

あとはボタンをクリックしたときの関数を2種類用意。

まずはデータベースにデータを登録する処理。
ボタンとしては「Write」とかかれたボタンです。

@IBAction func writeData(_ b: NSButton) {
	let appDel = NSApplication.shared.delegate as! AppDelegate
	let context = appDel.persistentContainer.viewContext
	let entity = NSEntityDescription.entity(forEntityName: "Entity", in: context)
	let newData = NSManagedObject(entity: entity!, insertInto: context)
	newData.setValue(Int16(IDnumber.stringValue), forKey: "id")
	newData.setValue(nameField.stringValue, forKey: "name")
	do {
		try context.save()
	} catch {
		print("Failed saving")
	}
}

これもStoryboard上ではボタンをつないでおきます。
で、その中身ですが、よくわからなかった。
でも、重要なのが、まず「let entity =〜」の部分の後ろの方にあるパーレンの中身。
「forEntityName:」の部分ですね。
ここで氷翠は引っかかっていました。この名前というのは、「testDB.xcdatamodeld」の中で定義した「ENTITES」のところの下の名前。今回は「Entity」としているので、ここで指定しておきます。
これが別の存在しない名前だと、定数「entity」の内容が「nil」となってしまいます。
そして、定数「newData」を用意します。
その下位の関数「setValue」にて、データを確保。「forKey」のところでフィールド名を指定してあげます。
その後はtry文の中身「try context.save()」で保存することができます。

@IBAction func readData(_ b: NSButton) {
	let appDel = NSApplication.shared.delegate as! AppDelegate
	let context = appDel.persistentContainer.viewContext
	let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Entity")
	request.returnsObjectsAsFaults = false
	do {
		let result = try context.fetch(request)
		for data in result as! [NSManagedObject] {
			let read_id = String(data.value(forKey: "id") as! Int16)
			let read_name = data.value(forKey: "name") as! String
			print(String(read_id)+" // "+read_name)
		}
		
	} catch {
		
		print("Failed")
	}
	
}

次にデータを呼び出す処理です。
最初の方はデータを追加するときと同じものです。

「let request = 〜」の部分は、要はデータを検索するためのSQL的なものらしい。
で、その結果が「do〜」文の中にある「let result = 〜」の部分になる。
結果は複数存在すると仮定して、それを「for文」によって繰り返し取り出し、出力しています。

今回はここまで!

長かった…

コメントを残す

メールアドレスが公開されることはありません。