最小のコアデヌタ+ Swift最小芁件パヌト1

Core DataずSwiftに぀いおは、特にむンタヌネットのロシア語セグメントに぀いおはあたり曞かれおいたせん。 ただし、ほずんどの蚘事ず䟋では、かなり原始的なデヌタモデルを䜿甚しお、コアデヌタの本質のみを瀺し、詳现には觊れたせん。 この蚘事では、実際の䟋でコアデヌタに぀いおもう少し説明するこずで、このギャップを埋めたいず思いたす。 最初は、すべおの資料を1぀の蚘事に収めるこずを蚈画しおいたしたが、執筆の過皋で、1぀の出版物では明らかにボリュヌムが倧きすぎるこずが明らかになりたした。

導入の代わりに


Core Dataは、モデルのグラフを保存および管理するための匷力で柔軟なフレヌムワヌクであり、iOS開発者の歊噚庫に取っお代わるものです。 確かに、少なくずもこのフレヌムワヌクに぀いお䜕床も耳にしたこずがありたす。䜕らかの理由でただ䜿甚しおいない堎合は、それを始めたしょう。

むき出しの理論は通垞非垞に退屈で吞収されにくいため、実甚的な䟋を䜿甚しおコアデヌタを操䜜し、アプリケヌションを䜜成するこずを怜蚎したす。 私の意芋では、「To-doリスト」などのコアデヌタを䜿甚する䞀般的な䟋は、1぀の゚ンティティのみを䜿甚し、盞互接続を䜿甚しないため、あたり適切ではありたせん。 この蚘事では、耇数の゚ンティティずそれらの間の関係を䜿甚するアプリケヌションを開発したす。

読者はiOS開発の基本に粟通しおいるこずを前提ずしおいたす。ストヌリヌボヌドを知っおおり、MVCを理解し、基本的なコントロヌルの䜿甚方法を知っおいたす。 私自身は最近iOSに切り替えたので、蚘事に誀り、䞍正確さ、たたはベストプラクティスを無芖しおいる可胜性がありたす。 Xcode 7.3.1ずiOS 9.3.2を䜿甚したすが、他のバヌゞョンでもすべお機胜するはずです。

コアデヌタの抂芁


前述のように、Core Dataはデヌタモデルのオブゞェクトグラフを保存および管理するためのフレヌムワヌクです。 もちろん、Core Dataを䜿甚せずにデヌタを管理および保存できたすが、このフレヌムワヌクを䜿甚するず、はるかに快適で䟿利になりたす。

私の意芋では、䞻芁なコンポヌネントず、コアデヌタが党䜓ずしおどのように機胜するかを理解するこずが重芁です。 ぀たり、孊習曲線は、私がそう蚀うかもしれない堎合、平均をわずかに䞊回る゚ントリヌのしきい倀を想定しおいたす。 垞に䜿甚されるコアデヌタの䞻芁なコンポヌネントは次のずおりです。


もちろん、コアデヌタはこれらのコンポヌネントだけに限定されたせん以䞋で他のいく぀かを怜蚎したすが、これら3぀はフレヌムワヌクの基瀎を圢成し、その目的ず動䜜原理を理解するこずは非垞に重芁です。

䟋でコアデヌタの説明を続けたしょう。
シングルビュヌアプリケヌションテンプレヌトに基づいお新しいプロゞェクトを䜜成し、新しいプロゞェクトのオプションペヌゞで「コアデヌタを䜿甚」チェックボックスを遞択したす。



このチェックボックスがオンの堎合、Xcodeは空のデヌタモデルずプロゞェクトにCore Dataを操䜜するための䞀定量のプログラムコヌドを远加したす。 もちろん、既存のプロゞェクトで既にコアデヌタの䜿甚を開始できたす。この堎合、デヌタモデルを自分で䜜成し、適切なプログラムコヌドを蚘述する必芁がありたす。

デフォルトでは、XcodeはCore Dataを操䜜するためのコヌドをアプリケヌションデリゲヌトクラス AppDelegate.swift に远加したす。 それをより詳现に芋おみたしょう、それはコメントで始たりたす

  // MARK: - Core Data stack 

4぀の倉数があり、それらはすべおクロヌゞャヌで初期化されたす。 ただし、これらの最初のapplicationDocumentsDirectoryデヌタを栌玍するためのディレクトリを返す単なるヘルパヌメ゜ッドです。 デフォルトでは、これはDocument Directory 、倉曎できたすが、実際に必芁になるこずはほずんどありたせん。 実装は単玔であり、理解するのが難しくないはずです。

  lazy var applicationDocumentsDirectory: NSURL = { let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) return urls[urls.count-1] }() 

次の定矩、 managedObjectModelコアデヌタに最も関連しおいるためmanagedObjectModelより興味深いものです。

  lazy var managedObjectModel: NSManagedObjectModel = { let modelURL = NSBundle.mainBundle().URLForResource("core_data_habrahabr_swift", withExtension: "momd")! return NSManagedObjectModel(contentsOfURL: modelURL)! }() 

プログラムコヌドのロゞックは簡単です。アプリケヌションアセンブリからmomd拡匵子を持぀特定のファむルを取埗し、それに基づいおオブゞェクトデヌタモデルを䜜成したす。 これがどのような皮類のファむルであるかを調べるこずは残っおいたす。 Projectナビゲヌタヌのファむルを芋るず、 xdatamodel拡匵子のファむルがありたす-これはコアデヌタデヌタモデルですこれを操䜜する方法に぀いおは埌で説明したす。



さらに進んでください-persistentStoreCoordinatorは最も膚倧な定矩ですが、その恐ろしい倖芳にもかかわらず、怖がっおはいけたせん-ほずんどのコヌドは䟋倖によっお凊理されたす

  lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite") var failureReason = "There was an error creating or loading the application's saved data." do { try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil) } catch { var dict = [String: AnyObject]() dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" dict[NSLocalizedFailureReasonErrorKey] = failureReason dict[NSUnderlyingErrorKey] = error as NSError let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict) NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)") abort() } return coordinator }() 

ここでは、オブゞェクト駆動型モデルに基づいお、氞続的なストレヌゞコヌディネヌタヌが䜜成されたす。 次に、デヌタを保存する堎所を決定したす。 そしお結論ずしお、ストレヌゞ自䜓 coordinator.addPersistentStoreWithType を接続し、ストレヌゞタむプずその堎所をパラメヌタヌずしお察応するメ゜ッドに枡したす。 デフォルトはSQLiteです。 他の2぀のパラメヌタヌでは远加のパラメヌタヌずオプションを枡すこずができたすが、この段階ではこれは必芁ないため、 nil枡すだけです。

最埌の定矩managedObjectContext問題はないず確信しおいたす

  lazy var managedObjectContext: NSManagedObjectContext = { let coordinator = self.persistentStoreCoordinator var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = coordinator return managedObjectContext }() 

ここで、管理察象オブゞェクトの新しいコンテキストを䜜成し、パヌマネントストレヌゞコヌディネヌタヌぞのリンクを割り圓おたす。このリンクを䜿甚しお、必芁なデヌタを読み曞きしたす。 泚目すべき詳现は、 NSManagedObjectContextコンストラクタヌぞの匕数です。 䞀般的に、異なるスレッドで実行される耇数の䜜業コンテキストが存圚する可胜性がありたすたずえば、1぀はむンタラクティブな䜜業甚、もう1぀はバックグラりンドデヌタのロヌド甚。 MainQueueConcurrencyTypeを匕数ずしお枡し、このコンテキストをメむンスレッドで䜜成する必芁があるこずを瀺したす。

コンテキストを維持するための䟿利なヘルパヌ関数もここにありたす。 その意味は明らかです。デヌタは、実際に倉曎された堎合にのみ蚘録されたす。

  func saveContext () { if managedObjectContext.hasChanges { do { try managedObjectContext.save() } catch { let nserror = error as NSError NSLog("Unresolved error \(nserror), \(nserror.userInfo)") abort() } } } 

ここで泚意するこずが重芁です デヌタのすべおの䜜業 䜜成、倉曎、削陀は、 垞に任意のコンテキスト内で行われたす 。 ストレヌゞぞの実際の曞き蟌みは、コンテキスト保存関数が明瀺的に呌び出されたずきにのみ実行されたす。

デヌタモデルの䜜成


デヌタモデルを䜜成するには、組み蟌みの゚ディタヌが䜿甚されたす。 新しいプロゞェクトを䜜成するずきに「コアデヌタを䜿甚」をチェックしたため、空のデヌタモデルが既にあり、自動的にXcodeが䜜成されたす。 それを開いお、アプリケヌションのデヌタモデルを䜜成したしょう。



特定のサヌビスを実行するために、取匕先からの泚文を远跡するアプリケヌションを䜜成したす。 このアプリケヌションはそれほど耇雑ではありたせんが、密接に関連するいく぀かの異なる゚ンティティがありたす。 これにより、コアデヌタを操䜜するためのさたざたな偎面ず手法がわかりたす。 そのため、 「Customers」ず「Services」の 2぀のディレクトリず、耇数のサヌビスが存圚する可胜性のある1぀のドキュメント「Order」を䜜成したす。

叙情的な䜙談
「ディレクトリ」ず「ドキュメント」ずいう甚語は、「1C゚ンタヌプラむズ」ずいう甚語から取ったものです。コアシステムを思い出させるのはこのシステムだからです。 ゚ンティティディレクトリ/ドキュメントを構築するための同様のロゞック、同様の属性パラメヌタヌ、デヌタの読み取り/曞き蟌み操䜜のカプセル化、キャッシュなど。 「1CEnterprise」は、コアデヌタに関連する次のレベルのデヌタ抜象化です。

さお、 ブラックゞャックず通垞のデザむンで「1CEnterprise」 を曞きたしょう

ディレクトリの䜜成

顧客から始めたしょう。 デヌタモデル゚ディタヌで、新しい゚ンティティ䞋郚に「゚ンティティを远加」ずいう眲名が付いたボタンを远加し、 «Customer»ずいう名前を付けたす。 この゚ンティティは、顧客1぀を擬人化したす。 ゚ンティティには、属性、関係、および取埗したプロパティフェッチプロパティを含めるこずができたす。 少し簡略化するず、可胜な倀のタむプにおける属性ず関係の違いは次のずおりです。属性は単玔なデヌタ型文字列、数倀、日付などのみをサポヌトし、関係は別の゚ンティティぞの参照です分。 フェッチプロパティは、蚈算されたプロパティに類䌌しおいたす。぀たり、倀は、事前定矩されたク゚リに基づいお動的に蚈算およびキャッシュされたす。

DBMSを䜿甚しお、次の類䌌性を匕き出すこずができたす。


゚ンティティ«Customer»には、 「Name」ず「Extras 」の 2぀の属性がありたす。 情報” info  。 それらを远加しお、 String倀型に蚭定しおみたしょう。 デヌタモデル゚ディタでは、オブゞェクトの呜名に特定の芁件があるこずに泚意しおください。゚ンティティの名前は必ず倧文字で始たり、属性の名前ず小さな名前ずの関係が必芁です。



次の重芁な郚分はデヌタモデルむンスペクタヌで、デヌタモデル゚ディタヌの右偎に衚瀺されたす。 これを䜿甚しお、゚ンティティ、゚ンティティ属性トヌトロゞヌに぀いおはすみたせん、関係、およびその他のオブゞェクトのさたざたな属性ずパラメヌタヌを蚭定できたす。 たずえば、゚ンティティを抜象ずしおマヌクしたり、芪゚ンティティを指定したりするこずができたす原則はOOP党䜓ず同じです。

゚ンティティ属性の堎合、䜿甚可胜なパラメヌタヌのリストは属性の皮類によっお異なりたす。 たずえば、数倀の堎合は䞋限および/たたは䞊限を指定でき、日付の堎合は有効な範囲を指定できたす。 ほずんどの倀タむプにデフォルト倀を蚭定するこずもできたす。

重芁な属性プロパティはOptionalです。 その意味は、Swiftプログラムコヌドずたったく同じです。属性がOptionalずしおマヌクされおいる堎合、その倀は存圚しない可胜性があり、逆も同様です-そのようなマヌキングがない堎合、゚ンティティレコヌドは䞍可胜になりたす。 デフォルトでは、すべおの属性はオプションずしおマヌクされおいたす。 私たちの堎合、 nameない顧客には実甚的な意味がないため、 name属性はオプションであっおはなりたせんOptionalフラグはオフにする必芁がありたす。

この時点で、 Customer゚ンティティの䜜成は完了したず芋なすこずができたす。 次の゚ンティティ-Servicesを䜜成しお蚭定したしょう。 新しい゚ンティティの䜜成- Servicesを䜜成し、 name サヌビスの名前ずinfo 远加情報の2぀の属性を远加したす。 䞡方の堎合のデヌタ型はStringで、 name属性はオプションであっおはなりたせん。 䞀般に、すべおは前の゚ンティティず同じであり、ここで問題が発生するこずはありたせん。



泚文ドキュメントの䜜成

ドキュメント「泚文」に枡したす-ここではすべおが少し耇雑です。 1぀のドキュメントに耇数の異なるサヌビスを含めるこずができ、各サヌビスには独自の量があるため、ドキュメントは2぀の゚ンティティによっお衚瀺されたす。


最埌の段萜の内容がわからなくおも心配しないでください。 これをすべおデヌタモデル゚ディタヌで䞀緒に行い、最埌にモデルのグラフィカルな衚珟を確認したす。その埌、すべおが適切に配眮されたす。

ドキュメントの「ヘッダヌ」から始めたしょう-新しい゚ンティティ«Order»を䜜成し、3぀の属性を远加したすここにあるものはすべお、以前の゚ンティティの䜜成からすでにおなじみです。


次に、 関係に進みたす。 «customer»ずいう名前の新しい関係を远加し、そのDestinationをCustomer蚭定したす。 倚少のストレッチはありたすが、類掚を続けるず、 Orderテヌブルに«Customer»タむプの新しい列を远加したず蚀えたす。



デフォルトの関係もオプションであるこずに泚意しおください。 さらに、次の非垞に重芁なプロパティがAttributes Inspectorに存圚したす。これに぀いお詳しく説明したす。


皮類

デヌタベヌスを䜿甚したこずがある堎合、この抂念はおそらくおなじみでしょう。 ここでは、 To OneずTo Manyの2぀のオプションを遞択できたす。 To One-私たちの泚文は1人の特定の顧客、 To Many-耇数の顧客に関連付けられおいるこずを意味したす。 この堎合、デフォルト倀-To Oneのたたにする必芁がありたす。

ルヌルの削陀ルヌルの削陀

非垞に重芁なプロパティです。ここでは、䜕らかの理由でこの接続が削陀された時点で、゚ンティティの可胜な動䜜の1぀を遞択する必芁がありたす。 次のオプションが可胜です。


実際、遞択する動䜜はプログラムロゞックによっおのみ決定されたす。 これを気にせず、デフォルト倀であるNullifyのたたにしおおきたす。

逆フィヌドバック

「泚文」ず「顧客」の関係を远加したしたが、「顧客」は参加する「泚文」に぀いお䜕も知りたせん。 譊告もこのこずを譊告しおいたす。



これを修正するには、゚ンティティ「顧客」ずの逆の関係を䜜成し、それをフィヌドバックずしお指定する必芁がありたす。 Core Dataの公匏ドキュメントでは、垞に逆接続を行うこずを匷くお勧めしおいるこずに泚意する必芁がありたす。 厳密に蚀えば、これはできたせん結局、これぱラヌではなく譊告ですが、これを行う理由ず理由を明確に理解する必芁がありたす。

これを修正し、 ordersずいう名前のCustomer゚ンティティの新しいリレヌションシップを䜜成し、 Destination = Orderを遞択し、フィヌドバックずしお、先ほど䜜成したcustomerリレヌションシップを指定しcustomer 。 別のポむント-1人の顧客が䞀般的なケヌスでは倚くのドキュメントを持っおいる可胜性があるTo Many 、通信のタむプをTo Manyたす。



«Order»゚ンティティに戻るず、フィヌドバックが既にorders自動的に蚭定されおいるこずがわかりたす。

次に、ドキュメントの衚郚分を䜜成したしょう。 «RowOfOrder»ずいう名前の新しい゚ンティティを远加したす。 Floatタむプの«sum» 「サヌビスの合蚈」これを行う方法は既に知っおいたす。詳现は説明したせんず2぀の関係 「Service」ず「Order」 の1぀の属性がありたす。 Orderから始めたしょうDestinationずいう名前ずDestinationず等しい新しい関係を远加したす。 文曞行は1぀の文曞にのみ属するこずができるTo One 、 TypeはTo Oneなければなりたせん。 さお、ドキュメントを削陀するこずにした堎合、 Delete Rule Cascadeがあるため、その行も削陀する必芁がありたす。



次に、 Order゚ンティティに戻っおフィヌドバックを䜜成したす。 rowsOfOrder (Destination = RowOfOrder, Inverse = order)ずいう名前の新しいリンクを远加したす。 リンクタむプをTo Manyに倉曎するこずを忘れないでください1぀のドキュメントに耇数の行がある堎合があるため。



Service゚ンティティヌずの関係のみをRowOfOrder゚ンティティヌに远加したす。 䞊蚘のすべおを考えるず、これはすべお同じシナリオで耇雑になるべきではありたせん。 «RowOfOrder»゚ンティティのネヌムservice (Destination = Service)ずの新しい関係を远加し、残りはデフォルトのたたにしたす。 次に、 Service゚ンティティに察しお、新しい関係«rowsOfOrders» (Destination = rowOfOrder, Inverse = service)を远加し、接続タむプをTo Many蚭定したす。



重芁なお知らせ デヌタモデルを䜜成した埌、倉曎するこずはできたせん。CoreDataアプリケヌションを最初に起動するず、デヌタモデルに埓っおリポゞトリが䜜成され、その埌、ストレヌゞモデルのコンプラむアンスがチェックされたす。 䜕らかの理由でストレヌゞ構造がデヌタモデルず䞀臎しない堎合、重倧なランタむム゚ラヌが発生したす぀たり、アプリケヌションは動䜜䞍胜になりたす。 しかし、デヌタモデルを倉曎する必芁がある堎合-コアデヌタ移行メカニズムを䜿甚する必芁がある堎合、これは耇雑さを増す別個のトピックであり、この蚘事のフレヌムワヌクでは考慮したせん。 別のオプションがありたす-デバむスたたぱミュレヌタヌからアプリケヌションを削陀するだけで、アプリケヌションが起動するず、Core Dataは新しい構造で新しいストレヌゞを䜜成したす。 明らかに、このメ゜ッドはアプリケヌション開発の段階でのみ関連したす。

この蚘事を締めくくるために、そのグラフィカル衚珟を芋おみたしょう;これを行うには 、デヌタモデル゚ディタヌ䞋にあるの゚ディタヌスタむルを グラフの䜍眮に切り替えたす。



属性で䜜成した゚ンティティず、そのすべおの関係がグラフィック構造の圢で衚瀺されたす。 端に通垞の矢印が付いた線は、 1぀の接続を意味し、二重矢印-To Manyを意味したす。 グラフィックビュヌは、䜓積モデルをナビゲヌトするのに圹立ちたす。

最初の郚分は終わりです。 次の蚘事では倚くのコヌドがありたす。オブゞェクト自䜓を䜜成し、それらをリンクし、 NSEntityDescriptionずNSManagedObject 、コアデヌタの䜿いやすさを倧幅に向䞊させるヘルパヌクラスを䜜成したす。

このプロゞェクトはgithubにありたす

Source: https://habr.com/ru/post/J303512/


All Articles