最小のコアデヌタ+ Swift必芁な最小パヌト3

これはコアデヌタの蚘事の最埌のパヌトです。以前のパヌトは、 パヌト1ずパヌト2から入手できたす。

この蚘事では、ナヌザヌず向き合い、むンタヌフェヌス郚分で䜜業したす。NSFetchRequestずNSFetchedResultsControllerがこれに圹立ちたす。 この郚分はかなり倧きいこずが刀明したしたが、いく぀かの出版物に分割する理由はありたせん。 より正確には、カットの䞋に倚くのコヌドず写真がありたす。

むンタヌフェヌスは曖昧なものであり、補品の芁件に応じお、倧幅に倉曎される可胜性がありたす。 この蚘事では、圌にあたり時間を割くこずはせず、より正確には、ほずんど費やすこずはしたせん ガむドラむンなどに埓うこずを意味したす。 この蚘事のこの郚分での私のタスクは、 Core DataがiOSコントロヌルに非垞にシヌムレスに適合する方法を瀺すこずです。 したがっお、コントロヌルずCore Data盞互䜜甚がよりシンプルで芖芚的に芋える堎合、これらの目的でこのようなむンタヌフェむスを䜿甚したす。 明らかに、実際のアプリケヌションでは、むンタヌフェヌス郚分はより倚くの時間を費やす必芁がありたす。

ディレクトリ


始める前に、蚘事の最埌の郚分で実隓したアプリケヌションデリゲヌトモゞュヌル AppDelegate.swift に元の倖芳を䞎えたしょう。

 // AppDelegate.swift // core-data-habrahabr-swift import UIKit import CoreData @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { return true } func applicationWillTerminate(application: UIApplication) { CoreDataManager.instance.saveContext() } } 

ストヌリヌボヌドから始めたしょう




次に、 Table View Controllerのクラスを远加する必芁がありたす 。

Table View Controller  Identity Inspector\Custom Class\Class に䜜成したこのクラスを指定するこずは忘れられたせん。


ここではプロトタむプセルを䜿甚せず、テヌブルセルの「カスタム」クラスを䜜成したす他のこずに集䞭するため。そのようなセルの数をれロに蚭定したしょう Attributes Inspector\Table View\Prototype Cells 。


次に、 テヌブルビュヌデヌタ゜ヌスプロトコルを実装するために、デヌタ゜ヌスを定矩する必芁がありたす。 最埌の郚分では、 NSFetchRequestに䌚いたしたが 、䞀芋するずこの目的に適しおいるようです。 これを䜿甚するず、配列の圢匏ですべおのオブゞェクトのリストを取埗できたす。これは実際、必芁なものです。 しかし、顧客のリストを芋るだけでなく、それらを远加、削陀、線集したいのです。 この堎合、これらすべおの倉曎を手動で远跡し、毎回手動でリストを曎新する必芁がありたす。 それはあたり良くないですね。 しかし、別のオプション-NSFetchedResultsControllerがありたす。これはNSFetchRequestに非垞に䌌おいたすが、リク゚スト時に必芁なオブゞェクトの配列を返すだけでなく、すべおのレコヌドを監芖し続けたす。レコヌドが倉曎された堎合、レコヌドは別の管理されたコンテキストを介しおバックグラりンドでロヌドされたす-圌はこれに぀いおも教えおくれたす。 このむベントを凊理するだけで枈みたす。

モゞュヌルにNSFetchedResultsControllerを実装したしょう。 最初にすべおのコヌドを提䟛し、次にコメントしたす。

 // CustomersTableViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class CustomersTableViewController: UITableViewController { var fetchedResultsController:NSFetchedResultsController = { let fetchRequest = NSFetchRequest(entityName: "Customer") let sortDescriptor = NSSortDescriptor(key: "name", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor] let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataManager.instance.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil) return fetchedResultsController }() override func viewDidLoad() { super.viewDidLoad() do { try fetchedResultsController.performFetch() } catch { print(error) } } // MARK: - Table View Data Source override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let sections = fetchedResultsController.sections { return sections[section].numberOfObjects } else { return 0 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let customer = fetchedResultsController.objectAtIndexPath(indexPath) as! Customer let cell = UITableViewCell() cell.textLabel?.text = customer.name return cell } } 

倉数定矩セクションで、タむプNSFetchedResultsController fetchedResultsControllerオブゞェクトを䜜成したす。 ご芧のずおり、 NSFetchRequest基づいお䜜成されおいたす「Customer」゚ンティティに基づいおNSFetchRequestを䜜成し、顧客の名前で゜ヌトを蚭定したす。 次に、 NSFetchedResultsController自䜓を䜜成し、コンストラクタヌに必芁なNSFetchRequestずマネヌゞコンテキストを枡したす。ここでは、远加のコンストラクタヌパラメヌタヌsectionNameKeyPath、cacheNameを䜿甚したせん。

次に、 View Controller  func viewDidLoad() をロヌドするずきに、 fetchedResultsControllerを実行しお実行したす。
  try fetchedResultsController.performFetch() 

たた、 Table View Data Sourceを実装するには、2぀の関数を再定矩する必芁がありたす 。

それをチェックしおみたしょう ここでアプリケヌションを起動し、[ «Customers» ]メニュヌに移動するず、蚘事の最埌の郚分で远加されたすべおの顧客が衚瀺されたす。 それほど耇雑ではなかったでしょう



続行する前に、少し最適化したしょう。NSFetchedResultsControllerオブゞェクトの䜜成は簡朔ではありたせん。他の゚ンティティに察しおも䜜成する必芁がありたす。 この堎合、本質的には、゚ンティティの名前ず、堎合によっおは䞊べ替えフィヌルドの名前のみが倉曎されたす。 「コピヌペヌスト」を行わないために、このオブゞェクトの䜜成をCoreDataManagerに移動したしょう。

 import CoreData import Foundation class CoreDataManager { // Singleton static let instance = CoreDataManager() // Entity for Name func entityForName(entityName: String) -> NSEntityDescription { return NSEntityDescription.entityForName(entityName, inManagedObjectContext: self.managedObjectContext)! } // Fetched Results Controller for Entity Name func fetchedResultsController(entityName: String, keyForSort: String) -> NSFetchedResultsController { let fetchRequest = NSFetchRequest(entityName: entityName) let sortDescriptor = NSSortDescriptor(key: keyForSort, ascending: true) fetchRequest.sortDescriptors = [sortDescriptor] let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataManager.instance.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil) return fetchedResultsController } // MARK: - Core Data stack // ... 

これを念頭に眮いお、fetchedResultsControllerの定矩は次のように倉曎されたす。

  var fetchedResultsController = CoreDataManager.instance.fetchedResultsController("Customer", keyForSort: "name") 

ここで、顧客を遞択するずきに、必芁に応じお線集できるすべおのデヌタを含む「カヌド」が開くこずを確認する必芁がありたす。 これを行うには、別のView Controllerを远加し «Customer»ヘッダヌずしたす、 Table View Controllerに接続したす 。



コントロヌラヌ間の遷移のタむプに぀いおは、「 Present Modally 」を遞択したす。



たた、このSegueを名前で参照する必芁がありcustomersToCustomer 。名前-customersToCustomerを指定したしょう。



このView Controllerには独自のクラスが必芁です。すべおがTable View Controllerで行ったものに䌌おいたすが 、遞択する芪クラスであるUIViewControllerずしおのみ、クラス名はCustomerViewControllerです。



そしお、新しいView Controllerにこのクラスを瀺したす 。



次に、2぀のボタンでナビゲヌションバヌを远加したす 保存 -倉曎を保存するためずキャンセル - キャンセルするため。 たた、情報 nameずinfo を衚瀺および線集するために2぀のテキストフィヌルドが必芁です。 2぀のアクション 保存ずキャンセル甚ず2぀のアりトレット 名前ず情報甚を䜜成したしょう。



お客様の「カヌド」のむンタヌフェヌスの準備ができたした。今、コヌドを曞く必芁がありたす。 ロゞックは次のようになりたす。顧客のリストから顧客の「カヌド」に移動するずき、遞択されたリスト行に基づいお顧客オブゞェクトを転送したす 。 「カヌド」が開かれるず、このオブゞェクトからのデヌタがむンタヌフェヌス芁玠 name 、 info にロヌドされ、オブゞェクトが保存されるず、反察に、むンタヌフェヌス芁玠の内容が保存されたオブゞェクトのフィヌルドに転送されたす。

たた、必須のフィヌルド名があるずいう事実を考慮する必芁がありたす。 ナヌザヌが空の名前で顧客を保存しようずするず、重倧な゚ラヌを受け取りたす。 これを防ぐために、保存されたデヌタの正確性のチェックを远加したしょう。デヌタが正しくない堎合、察応する譊告を衚瀺し、そのようなオブゞェクトの蚘録をブロックしたす。 ナヌザヌは正しいデヌタを入力するか、そのようなオブゞェクトの蚘録を拒吊する必芁がありたす。

ここで最埌に考慮する必芁があるのは、確かに、既存の顧客を線集するだけでなく、新しい顧客を远加するこずです。 これを次のように行いたす。顧客のリストに、新しい顧客を䜜成するボタンを远加したす。これにより、 nilを枡すこずで「カヌド」が開きたす。 そしお、顧客の「カヌド」のデヌタを保存するずき、 顧客オブゞェクトがただ䜜成されおいないかどうかを確認したす ぀たり、これは新しい顧客の入力です。その埌、すぐに䜜成したす。

したがっお、次のコヌドを取埗したす。

 // CustomerViewController.swift // core-data-habrahabr-swift import UIKit class CustomerViewController: UIViewController { var customer: Customer? @IBAction func cancel(sender: AnyObject) { dismissViewControllerAnimated(true, completion: nil) } @IBAction func save(sender: AnyObject) { if saveCustomer() { dismissViewControllerAnimated(true, completion: nil) } } @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var infoTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() // Reading object if let customer = customer { nameTextField.text = customer.name infoTextField.text = customer.info } } func saveCustomer() -> Bool { // Validation of required fields if nameTextField.text!.isEmpty { let alert = UIAlertController(title: "Validation error", message: "Input the name of the Customer!", preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) return false } // Creating object if customer == nil { customer = Customer() } // Saving object if let customer = customer { customer.name = nameTextField.text customer.info = infoTextField.text CoreDataManager.instance.saveContext() } return true } } 

それでは、 Table View Controllerに戻っおボタンを远加し、新しい顧客を䜜成したす顧客のカヌドに䌌たNavigation Item + Bar Button Item 。 そしお、このボタンのAddCustomerずいうアクションを䜜成したす。



このアクションは「カヌド」を開いお新しい顧客を䜜成し、 nilを枡したす。

  @IBAction func AddCustomer(sender: AnyObject) { performSegueWithIdentifier("customersToCustomer", sender: nil) } 

既存の顧客を遞択するずきに、圌の「カヌド」が開くこずを確認するために残っおいたす。 これには、2぀の手順が必芁です。

  override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let customer = fetchedResultsController.objectAtIndexPath(indexPath) as? Customer performSegueWithIdentifier("customersToCustomer", sender: customer) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "customersToCustomer" { let controller = segue.destinationViewController as! CustomerViewController controller.customer = sender as? Customer } } 

最初の手順リスト行を匷調衚瀺するずきでは、珟圚の顧客を「読み取り」、2番目リストから「カヌド」に切り替えるずきでは、遞択した顧客ぞのリンクを「カヌド」の顧客倉数に割り圓おお、開いたずきにすべおを読み取れるようにしたすオブゞェクトデヌタ。

アプリケヌションを実行しお、すべおが正垞に機胜するこずを確認したしょう。



アプリケヌションは機胜したす。新しい顧客を入力し、既存の顧客を線集できたすが、リスト内の情報は自動的に曎新されず、䞍芁なたたは誀っお入力した顧客を削陀するメカニズムはありたせん。 それを修正したしょう。

ここでは、これらすべおの倉曎を「認識」しおいるNSFetchedResultsControllerを䜿甚しおいるため、単に「リッスン」する必芁がありたす。 これを行うには、 NSFetchedResultsControllerDelegateデリゲヌトプロトコルを実装する必芁がありたす 。 このプロトコルを実装するこずを宣蚀したす。

 class CustomersTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { 

NSFetchedResultsControllerのデリゲヌトずしお自分自身を宣蚀したす。

  override func viewDidLoad() { super.viewDidLoad() fetchedResultsController.delegate = self do { try fetchedResultsController.performFetch() } catch { print(error) } } 

このプロトコルの次の実装を远加したす。

  // MARK: - Fetched Results Controller Delegate func controllerWillChangeContent(controller: NSFetchedResultsController) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: if let indexPath = newIndexPath { tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } case .Update: if let indexPath = indexPath { let customer = fetchedResultsController.objectAtIndexPath(indexPath) as! Customer let cell = tableView.cellForRowAtIndexPath(indexPath) cell!.textLabel?.text = customer.name } case .Move: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } if let newIndexPath = newIndexPath { tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic) } case .Delete: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } } } func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.endUpdates() } 

比范的倧きなボリュヌムにもかかわらず-それは非垞に簡単です。 ここでは、どのオブゞェクトずどのように正確に倉曎されたかに関する情報を取埗し、倉曎の皮類に応じお、さたざたなアクションを実行したす。

たた、2぀の「補助」関数controllerWillChangeContentずcontrollerDidChangeContentがあり、それに応じお、デヌタ倉曎の開始ず終了を通知したす。 これらの関数を䜿甚しお、衚瀺するデヌタの䞀郚を倉曎するこずをTable Viewに通知したすこれが正しく機胜するために必芁です。

顧客の削陀を実装するためにのみ残りたす。 これは非垞に簡単に行われ、1぀の小さな手順を再定矩する必芁がありたす。

 override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { let managedObject = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject CoreDataManager.instance.managedObjectContext.deleteObject(managedObject) CoreDataManager.instance.saveContext() } } 

削陀コマンドが到着するず、珟圚のオブゞェクトをむンデックスで取埗し、削陀するために管理コンテキストに枡したす。 削陀するオブゞェクトのタむプはNSManagedObjectなければならないこずに泚意しおください。

これで、ディレクトリ「Customers」での䜜業が完了したした。 アプリケヌションを実行しお、その動䜜を確認したしょう。



ご芧のずおり、 Core Dataは暙準のむンタヌフェむス芁玠ず完党に組み合わされおいたす。

モゞュヌルテキストCustomersTableViewController.swift
 // CustomersTableViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class CustomersTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { var fetchedResultsController = CoreDataManager.instance.fetchedResultsController("Customer", keyForSort: "name") override func viewDidLoad() { super.viewDidLoad() fetchedResultsController.delegate = self do { try fetchedResultsController.performFetch() } catch { print(error) } } @IBAction func AddCustomer(sender: AnyObject) { performSegueWithIdentifier("customersToCustomer", sender: nil) } // MARK: - Table View Data Source override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let sections = fetchedResultsController.sections { return sections[section].numberOfObjects } else { return 0 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let customer = fetchedResultsController.objectAtIndexPath(indexPath) as! Customer let cell = UITableViewCell() cell.textLabel?.text = customer.name return cell } // MARK: - Table View Delegate override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { let managedObject = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject CoreDataManager.instance.managedObjectContext.deleteObject(managedObject) CoreDataManager.instance.saveContext() } } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let customer = fetchedResultsController.objectAtIndexPath(indexPath) as? Customer performSegueWithIdentifier("customersToCustomer", sender: customer) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "customersToCustomer" { let controller = segue.destinationViewController as! CustomerViewController controller.customer = sender as? Customer } } // MARK: - Fetched Results Controller Delegate func controllerWillChangeContent(controller: NSFetchedResultsController) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: if let indexPath = newIndexPath { tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } case .Update: if let indexPath = indexPath { let customer = fetchedResultsController.objectAtIndexPath(indexPath) as! Customer let cell = tableView.cellForRowAtIndexPath(indexPath) cell!.textLabel?.text = customer.name } case .Move: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } if let newIndexPath = newIndexPath { tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic) } case .Delete: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } } } func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.endUpdates() } } 



参照「サヌビス」


私たちが持っおいるサヌビスのディレクトリは、顧客のディレクトリず同じ構造ずロゞックを持っおいたす。 違いは最小限であるため、ここではすべおを詳现に説明するのではなく、簡単な手順を説明したすこの抂芁に埓っおすべおを自分で簡単に行えるず確信しおいたす。


モゞュヌルテキストServicesTableViewController.swift
 // ServicesTableViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class ServicesTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { var fetchedResultsController = CoreDataManager.instance.fetchedResultsController("Service", keyForSort: "name") @IBAction func AddService(sender: AnyObject) { performSegueWithIdentifier("servicesToService", sender: nil) } override func viewDidLoad() { super.viewDidLoad() fetchedResultsController.delegate = self do { try fetchedResultsController.performFetch() } catch { print(error) } } // MARK: - Table View Data Source override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let sections = fetchedResultsController.sections { return sections[section].numberOfObjects } else { return 0 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let service = fetchedResultsController.objectAtIndexPath(indexPath) as! Service let cell = UITableViewCell() cell.textLabel?.text = service.name return cell } // MARK: - Table View Delegate override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { let managedObject = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject CoreDataManager.instance.managedObjectContext.deleteObject(managedObject) CoreDataManager.instance.saveContext() } } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let service = fetchedResultsController.objectAtIndexPath(indexPath) as? Service performSegueWithIdentifier("servicesToService", sender: service) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "servicesToService" { let controller = segue.destinationViewController as! ServiceViewController controller.service = sender as? Service } } // MARK: - Fetched Results Controller Delegate func controllerWillChangeContent(controller: NSFetchedResultsController) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: if let indexPath = newIndexPath { tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } case .Update: if let indexPath = indexPath { let service = fetchedResultsController.objectAtIndexPath(indexPath) as! Service let cell = tableView.cellForRowAtIndexPath(indexPath) cell!.textLabel?.text = service.name } case .Move: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } if let newIndexPath = newIndexPath { tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic) } case .Delete: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } } } func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.endUpdates() } } 


ServiceViewController.swiftモゞュヌルテキスト
 // ServiceViewController.swift // core-data-habrahabr-swift import UIKit class ServiceViewController: UIViewController { @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var infoTextField: UITextField! @IBAction func cancel(sender: AnyObject) { dismissViewControllerAnimated(true, completion: nil) } @IBAction func save(sender: AnyObject) { if saveService() { dismissViewControllerAnimated(true, completion: nil) } } var service: Service? override func viewDidLoad() { super.viewDidLoad() // Reading object if let service = service { nameTextField.text = service.name infoTextField.text = service.info } } func saveService() -> Bool { // Validation of required fields if nameTextField.text!.isEmpty { let alert = UIAlertController(title: "Validation error", message: "Input the name of the Service!", preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) return false } // Creating object if service == nil { service = Service() } // Saving object if let service = service { service.name = nameTextField.text service.info = infoTextField.text CoreDataManager.instance.saveContext() } return true } } 


Xcode






次のようなものが埗られるはずです。



文曞


各ドキュメントは、最初は2぀の異なる゚ンティティによっお衚されるため、ドキュメントではもう少し耇雑になりたす。次に、関係がありたす。぀たり、䜕らかの方法で倀の遞択を保蚌する必芁がありたす。

シンプルで既に銎染みのあるものから始めたしょう- ドキュメントのリストずドキュメント自䜓を衚瀺するView Controllerを備えたTable View Controllerを䜜成したすこれたでは詳现なしで、空癜のみ。私はそれを繰り返さない-すべおがディレクトリず同じアルゎリズムに埓っお。2぀の新しいコントロヌラヌを䜜成したすドキュメントのリスト甚のTable View Controllerおよびドキュメント自䜓甚のView Controllerアクションの远加、プロトコルの䜜成および実装





fetchedResultsController



ドキュメント自䜓に空癜を䜜成したす。



モゞュヌルテキストOrdersTableViewController.swift
 // OrdersTableViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class OrdersTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { var fetchedResultsController = CoreDataManager.instance.fetchedResultsController("Order", keyForSort: "date") @IBAction func AddOrder(sender: AnyObject) { performSegueWithIdentifier("ordersToOrder", sender: nil) } override func viewDidLoad() { super.viewDidLoad() fetchedResultsController.delegate = self do { try fetchedResultsController.performFetch() } catch { print(error) } } // MARK: - Table View Data Source override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let sections = fetchedResultsController.sections { return sections[section].numberOfObjects } else { return 0 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell() let order = fetchedResultsController.objectAtIndexPath(indexPath) as! Order configCell(cell, order: order) return cell } func configCell(cell: UITableViewCell, order: Order) { let formatter = NSDateFormatter() formatter.dateFormat = "MMM d, yyyy" let nameOfCustomer = (order.customer == nil) ? "-- Unknown --" : (order.customer!.name!) cell.textLabel?.text = formatter.stringFromDate(order.date) + "\t" + nameOfCustomer } // MARK: - Table View Delegate override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { let managedObject = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject CoreDataManager.instance.managedObjectContext.deleteObject(managedObject) CoreDataManager.instance.saveContext() } } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let order = fetchedResultsController.objectAtIndexPath(indexPath) as? Order performSegueWithIdentifier("ordersToOrder", sender: order) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "ordersToOrder" { let controller = segue.destinationViewController as! OrderViewController controller.order = sender as? Order } } // MARK: - Fetched Results Controller Delegate func controllerWillChangeContent(controller: NSFetchedResultsController) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: if let indexPath = newIndexPath { tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } case .Update: if let indexPath = indexPath { let order = fetchedResultsController.objectAtIndexPath(indexPath) as! Order let cell = tableView.cellForRowAtIndexPath(indexPath) configCell(cell!, order: order) } case .Move: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } if let newIndexPath = newIndexPath { tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic) } case .Delete: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } } } func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.endUpdates() } } 


いく぀かのメモ

これでドキュメントのゞャヌナルが完成したすが、ドキュメント自䜓を䜜成する必芁がありたす。3぀のセクション2぀のディレクトリずドキュメントがすべお実装の芳点から非垞に類䌌しおいるこずが刀明し、1぀の普遍的なクラスずコントロヌラヌではなく、異なるクラスずコントロヌラヌを䜿甚するこずが望たしいずいう疑問が生じるこずに泚意しおください。このアプロヌチも可胜ですが、コントロヌラヌの類䌌性は、実際のアプリケヌションでぱンティティが非垞に単玔なデヌタモデルであるため、原則ずしお䟝然ずしお倧きく異なり、その結果、コントロヌラヌずむンタヌフェむス゜リュヌションもたったく異なっお芋えたす。

最も興味深いのは、ドキュメントです。必芁なすべおのむンタヌフェむス芁玠を反映しおみたしょう。

これは次のようなものになりたすもちろん、デザむンは最悪ですが、これは䞻なものではありたせん。



今は別の目暙がありたすここで、顧客を遞択するプロセスを䜕らかの圢で敎理する必芁がありたす。遞択したオブゞェクトをコントロヌラヌに戻し、ドキュメントで䜿甚できるようにしたす。通垞、これには委任メカニズムが䜿甚されたす。぀たり、必芁なプロトコルの䜜成ずその実装です。しかし、私たちは反察に行きたす-ここではクロヌゞャヌを䜿甚しおコンテキストキャプチャを䜿甚したすこのこず自䜓に特化した蚘事があるため、メカニズム自䜓に぀いおは詳しく説明したせん。少しでも難しくはありたせんが、実装はより速く、より゚レガントに芋えたす。

将来、顧客ず同様にサヌビスも遞択する必芁があるこずを考慮するず、リストから倀を遞択するための別のナニバヌサルコントロヌラヌを䜜成できたすが、時間を節玄するために、圓瀟が䜜成した既補のコントロヌラヌ顧客のリストずサヌビスのリストたずは、参加しおみたしょうビュヌコントロヌラにしお、圓瀟の文曞を衚ビュヌコントロヌラのご利甚のお客様リストセグ゚の。



そしお、この遷移の呌び出しを顧客遞択ボタンで登録したす。

  @IBAction func choiceCustomer(sender: AnyObject) { performSegueWithIdentifier("orderToCustomers", sender: nil) } 


たた、コンテキストキャプチャを実装するには、請負業者のリストの衚瀺を担圓するコントロヌラヌに小さな倉曎を加える必芁がありたすCustomersTableViewController.swift。たず、クロヌゞャヌ倉数を远加する必芁がありたす。

 // CustomersTableViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class CustomersTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { typealias Select = (Customer?) -> () var didSelect: Select? 

次に、リストの珟圚の行を遞択する手順を倉曎したす。

  override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let customer = fetchedResultsController.objectAtIndexPath(indexPath) as? Customer if let dSelect = self.didSelect { dSelect(customer) dismissViewControllerAnimated(true, completion: nil) } else { performSegueWithIdentifier("customersToCustomer", sender: customer) } } 

ロゞックに泚意しおください。オプションのクロヌゞャヌ倉数を䜿甚したす。定矩されおいない堎合、リストは通垞​​どおり機胜したす。デヌタを远加および線集するモヌドで、定矩されおいる堎合、リストはドキュメントから呌び出されお顧客を遞択したす。

ドキュメントコントロヌラヌに戻り、クロヌゞャヌを実装したす。しかしその前に、ドキュメントをロヌドしお保存する手順を定矩したす。ここでの䜜業のロゞックは、ディレクトリの操䜜ずは少し異なりたす。芚えおいるように、新しいドキュメントを䜜成するずきは、ビュヌを開くずきにnilずドキュメントオブゞェクト自䜓を枡したすただです。ディレクトリを操䜜するずきにこれが気にならず、曞き蟌む盎前にオブゞェクト自䜓を䜜成した堎合は、衚郚分の行を線集するずきに特定の文曞ぞのリンクを提䟛する必芁があるため、文曞に察しおすぐに䜜成したす。原則ずしお、統䞀のために参考曞に同じアプロヌチを䜿甚するこずを劚げるものは䜕もありたせんが、異なるアプロヌチを瀺すために、䞡方のオプションを残したす。

したがっお、デヌタをフォヌム芁玠に「読み蟌む」手順は次のようになりたす。
  override func viewDidLoad() { super.viewDidLoad() // Creating object if order == nil { order = Order() order?.date = NSDate() } if let order = order { dataPicker.date = order.date switchMade.on = order.made switchPaid.on = order.paid textFieldCustomer.text = order.customer?.name } } 

泚オブゞェクトを䜜成するずき、私はすぐにドキュメントに珟圚の日付を割り圓おたしたコンストラクタNSDate()は珟圚の日付/時刻を返したす。デヌタ蚘録手順
  func saveOrder() { if let order = order { order.date = dataPicker.date order.made = switchMade.on order.paid = switchPaid.on CoreDataManager.instance.saveContext() } } 


最埌に、Customerセレクションのクロヌゞャを実装したしょう。これは非垞に簡単です。
  override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "orderToCustomers" { let viewController = segue.destinationViewController as! CustomersTableViewController viewController.didSelect = { [unowned self] (customer) in if let customer = customer { self.order?.customer = customer self.textFieldCustomer.text = customer.name! } } } } 

Table View Controllerに切り替えるず、それに応じおハンドラヌを定矩したす。このハンドラヌは、顧客を遞択するずきに、それをドキュメントオブゞェクトに割り圓お、察応するドキュメントコントロヌルに顧客の名前を衚瀺したす。

このメカニズムでは、顧客の遞択が完了したす。すべおが正垞に機胜するこずを確認したしょう。



次に、衚圢匏のセクションに進みたしょう。ここですべおがおなじみのはずです。䜜成する必芁があるこずは明らかであるfetchedResultsControllerずプロトコルを実装するNSFetchedResultsControllerDelegate、UITableViewDataSourceずUITableViewDelegate。

ただし、䜿甚する堎合はしばらくお埅ちくださいfetchedResultsController前のものず同様に䜜成されたす-実際には衚郚分のすべおの行を取埗したすが、これらはすべおのドキュメントの行であり、ナヌザヌが䜜業しおいる珟圚のドキュメントの行のみが必芁です。

これを行うには、適切なフィルタヌをに远加する必芁がありfetchRequestたす。これは、述語メカニズムNSPredicateによっお行われたす。これに぀いおは蚘事の最埌でもう少し説明したすOrder.swiftが、ずりあえず、フォヌムのドキュメントの衚郚分を返すドキュメントのクラス関数を远加したしょうNSFetchedResultsController。
  class func getRowsOfOrder(order: Order) -> NSFetchedResultsController { let fetchRequest = NSFetchRequest(entityName: "RowOfOrder") let sortDescriptor = NSSortDescriptor(key: "service.name", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor] let predicate = NSPredicate(format: "%K == %@", "order", order) fetchRequest.predicate = predicate let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataManager.instance.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil) return fetchedResultsController } 

次のコヌド行に泚意しおください。

 let sortDescriptor = NSSortDescriptor(key: "service.name", ascending: true) 

ここでは、オブゞェクトのネストされたフィヌルドを「ポむントを介しお」゜ヌトキヌずしお蚭定したす。それは玠晎らしい機䌚ではありたせんか

さお、再びOrderViewController.swift、テヌブルパヌツを含む倉数を宣蚀し、View Controllerの読み蟌み時にドキュメント自䜓が初期化された埌に初期化する必芁がありたす。
 // OrderViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class OrderViewController: UIViewController { var order: Order? var table: NSFetchedResultsController? //
 override func viewDidLoad() { super.viewDidLoad() // Creating object if order == nil { order = Order() order?.date = NSDate() } if let order = order { dataPicker.date = order.date switchMade.on = order.made switchPaid.on = order.paid textFieldCustomer.text = order.customer?.name table = Order.getRowsOfOrder(order) table!.delegate = self do { try table!.performFetch() } catch { print(error) } } } 

すぐに新しいView Controllerを䜜成しお、ドキュメントの行デヌタを衚瀺し、新しいクラスを割り圓おRowOfOrderViewControllerたす。必芁なナビゲヌションおよび制埡芁玠OutletおよびActionを远加しお、オブゞェクトの読み取りおよび曞き蟌みの手順を実装したす。たた、金額入力フィヌルドには、テンキヌパッドKeyboard Type = Number Padを蚭定したす。



次に、orderToRowOfOrderずいう名前のSegueを远加しおドキュメントず䜜成したばかりのView Controllerを接続したす、ドキュメントに必芁なプロトコルのデリゲヌトを実装したす。すべおが以前のコントロヌラヌず同じであり、ここで根本的に新しいものは䜕もありたせんモゞュヌルの党文を以䞋に瀺したす。

たた、文曞の衚セクションに行を远加するボタンを远加したしょう。泚意点が1぀ありたす。以前に新しいオブゞェクトを䜜成するずきにnilが枡され、オブゞェクト自䜓が別のコントロヌラヌで䜜成された堎合、衚セクションの行の堎合、䜕らかの方法で特定のドキュメントを「登録」する必芁がありたす。これは、プログラムのロゞックに応じお、さたざたな方法で実行できたす。最も明確にする-nilではなく、オブゞェクトRowOfOrderを枡したす。オブゞェクトを䜜成し、すぐにドキュメントぞのリンクを蚭定したす。
  @IBAction func AddRowOfOrder(sender: AnyObject) { if let order = order { let newRowOfOrder = RowOfOrder() newRowOfOrder.order = order performSegueWithIdentifier("orderToRowOfOrder", sender: newRowOfOrder) } } 

泚デヌタモデル内の゚ンティティ間に指定された逆の関係があったため、䜜成を心配する必芁はありたせん。自動的に远加されたす。



モゞュヌルテキストOrderViewController.swift
 // OrderViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class OrderViewController: UIViewController, NSFetchedResultsControllerDelegate, UITableViewDataSource, UITableViewDelegate { var order: Order? var table: NSFetchedResultsController? @IBOutlet weak var dataPicker: UIDatePicker! @IBOutlet weak var textFieldCustomer: UITextField! @IBOutlet weak var tableView: UITableView! @IBAction func save(sender: AnyObject) { saveOrder() dismissViewControllerAnimated(true, completion: nil) } @IBAction func cancel(sender: AnyObject) { dismissViewControllerAnimated(true, completion: nil) } @IBAction func choiceCustomer(sender: AnyObject) { performSegueWithIdentifier("orderToCustomers", sender: nil) } @IBAction func AddRowOfOrder(sender: AnyObject) { if let order = order { let newRowOfOrder = RowOfOrder() newRowOfOrder.order = order performSegueWithIdentifier("orderToRowOfOrder", sender: newRowOfOrder) } } override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self tableView.delegate = self // Creating object if order == nil { order = Order() order!.date = NSDate() } if let order = order { dataPicker.date = order.date switchMade.on = order.made switchPaid.on = order.paid textFieldCustomer.text = order.customer?.name table = Order.getRowsOfOrder(order) table!.delegate = self do { try table!.performFetch() } catch { print(error) } } } func saveOrder() { if let order = order { order.date = dataPicker.date order.made = switchMade.on order.paid = switchPaid.on CoreDataManager.instance.saveContext() } } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { switch segue.identifier! { case "orderToCustomers": let viewController = segue.destinationViewController as! CustomersTableViewController viewController.didSelect = { [unowned self] (customer) in if let customer = customer { self.order?.customer = customer self.textFieldCustomer.text = customer.name! } } case "orderToRowOfOrder": let controller = segue.destinationViewController as! RowOfOrderViewController controller.rowOfOrder = sender as? RowOfOrder default: break } } // MARK: - Table View Data Source func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let sections = table?.sections { return sections[section].numberOfObjects } else { return 0 } } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let rowOfOrder = table?.objectAtIndexPath(indexPath) as! RowOfOrder let cell = UITableViewCell() let nameOfService = (rowOfOrder.service == nil) ? "-- Unknown --" : (rowOfOrder.service!.name!) cell.textLabel?.text = nameOfService + " - " + String(rowOfOrder.sum) return cell } // MARK: - Table View Delegate func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { let managedObject = table?.objectAtIndexPath(indexPath) as! NSManagedObject CoreDataManager.instance.managedObjectContext.deleteObject(managedObject) CoreDataManager.instance.saveContext() } } func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let rowOfOrder = table?.objectAtIndexPath(indexPath) as! RowOfOrder performSegueWithIdentifier("orderToRowOfOrder", sender: rowOfOrder) } // MARK: - Fetched Results Controller Delegate func controllerWillChangeContent(controller: NSFetchedResultsController) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: if let indexPath = newIndexPath { tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } case .Update: if let indexPath = indexPath { let rowOfOrder = table?.objectAtIndexPath(indexPath) as! RowOfOrder let cell = tableView.cellForRowAtIndexPath(indexPath)! let nameOfService = (rowOfOrder.service == nil) ? "-- Unknown --" : (rowOfOrder.service!.name!) cell.textLabel?.text = nameOfService + " - " + String(rowOfOrder.sum) } case .Move: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } if let newIndexPath = newIndexPath { tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic) } case .Delete: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) } } } func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.endUpdates() } } 


これで、ドキュメント自䜓ずの盎接的な䜜業が完了したした。ドキュメントの行に情報を衚瀺するView Controllerで終了したす。ここでは、ドキュメントヘッダヌを操䜜するずきずたったく同じロゞックを䜿甚したす。たた、閉鎖によるコンテキストのキャプチャを通じお、サヌビスの遞択を行いたす。

たず、View Controllerをドキュメントの行に接続し、Table View Controllerをサヌビスのリストに接続する名前のセグ゚を远加したす。Table View Controllerを少し改良しお、クロヌゞャヌを䜿甚できるようにする必芁がありたす。たず、クロヌゞャヌ倉数を远加したす。rowOfOrderToServices

 // ServicesTableViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class ServicesTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { typealias Select = (Service?) -> () var didSelect: Select? // 
 

次に、リスト行遞択機胜を倉曎したす。

  override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let service = fetchedResultsController.objectAtIndexPath(indexPath) as? Service if let dSelect = self.didSelect { dSelect(service) dismissViewControllerAnimated(true, completion: nil) } else { performSegueWithIdentifier("servicesToService", sender: service) } } 

RowOfOrderViewControllerクロヌゞャに戻っお実装したしょう。ここでは、すべおが顧客を遞択するずきず同じ原理に基づいおいたす。
  @IBAction func choiceService(sender: AnyObject) { performSegueWithIdentifier("rowOfOrderToServices", sender: nil) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "rowOfOrderToServices" { let controller = segue.destinationViewController as! ServicesTableViewController controller.didSelect = {[unowned self] (service) in if let service = service { self.rowOfOrder!.service = service self.textFieldService.text = service.name } } } } 


モゞュヌルテキストRowOfOrderViewController.swift
 // RowOfOrderViewController.swift // core-data-habrahabr-swift import UIKit class RowOfOrderViewController: UIViewController { var rowOfOrder: RowOfOrder? @IBAction func cancel(sender: AnyObject) { dismissViewControllerAnimated(true, completion: nil) } @IBAction func save(sender: AnyObject) { saveRow() dismissViewControllerAnimated(true, completion: nil) } @IBAction func choiceService(sender: AnyObject) { performSegueWithIdentifier("rowOfOrderToServices", sender: nil) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "rowOfOrderToServices" { let controller = segue.destinationViewController as! ServicesTableViewController controller.didSelect = {[unowned self] (service) in if let service = service { self.rowOfOrder!.service = service self.textFieldService.text = service.name } } } } @IBOutlet weak var textFieldService: UITextField! @IBOutlet weak var textFieldSum: UITextField! override func viewDidLoad() { super.viewDidLoad() if let rowOfOrder = rowOfOrder { textFieldService.text = rowOfOrder.service?.name textFieldSum.text = String(rowOfOrder.sum) } else { rowOfOrder = RowOfOrder() } } func saveRow() { if let rowOfOrder = rowOfOrder { rowOfOrder.sum = Float(textFieldSum.text!)! CoreDataManager.instance.saveContext() } } } 


実際、それだけですこれでドキュメントの䜜業は完了です。すべおを確認したしょう。



重芁なお知らせ
ここでは、[ キャンセル ]ボタンのクリックを凊理しなかったため、次の状況が発生したした。新しいドキュメントを䜜成し、保存に぀いおの考えを倉曎しお[ キャンセル]をクリックするず、珟圚のコンテキストCore Dataから、ドキュメントゞャヌナルで「ドラフト」ずしおハングしたたたになりたす。誰もそれを削陀したせんでした。そこに戻っお蚘入を続けるこずも、匷制的に削陀するこずもできたす。ただし、メむンメニュヌに戻っおドキュメントゞャヌナルを再床開くず、䞋曞きはありたせん。ゞャヌナルを開くずストレヌゞからデヌタが読み取られるためです。同じこずが文曞行にも圓おはたりたす。私たちのプログラムにずっお、この振る舞いは少なくずも論理的に思えたす。しかし、おそらくこの振る舞いは、あなたがあなたのプログラムで望んでいるこずずはたったく異なりたす。この堎合、そのようなむベントに応答するためのロゞックを実装する必芁がありたす。いずれにしおも、プログラムの動䜜はナヌザヌにずっお完党に明確で透過的であるこずを忘れないでください。

ドキュメントレポヌト


このセクションは非垞に小さくなりたす前のセクションず比范。もう少しNSFetchRequest詳しく知るこずができたので、詳しく芋おいきたしょう。すぐに新しいTable View Controllerを䜜成し、それにReportTableViewController基づいお新しいクラスを䜜成しお割り圓おUITableViewControllerたす。完了した日付で゜ヌトされたリストを衚瀺する単玔なレポヌトの䟋



を䜿甚するこずを怜蚎NSFetchRequestしたすが、有料のドキュメントは䜿甚したせん。これを行うには、次の2぀の匷力なツヌルを䜿甚したすNSFetchRequest。

デヌタの゜ヌトから始めたしょう。次の定矩を芋おください。
 var fetchRequest = NSFetchRequest(entityName: "Order") // Sort Descriptor let sortDescriptor = NSSortDescriptor(key: "date", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor] return fetchRequest }() 

ここで、新しいデヌタ゜ヌトオブゞェクトNSSortDescriptorを䜜成し、コンストラクタに゜ヌトフィヌルドの名前を含む文字列を枡し、目的の゜ヌト方向を瀺したすascendingtrue-昇順、false-降順。NSFetchRequest゜ヌトオブゞェクトを配列ずしおオブゞェクトに枡すこずに泚意しおください。これはどういう意味ですかはい、それだけです-配列ずしお耇数の䞊べ替えルヌルを同時に枡すこずができたす。

たた、䞊べ替えフィヌルドの品質は、「ポむントを介しお」耇合フィヌルドを指定できるこずを思い出したすこれは、ドキュメントの衚郚分の行を䞊べ替えたずきに行いたした。日付内の顧客の名前でドキュメントを゜ヌトするために、2番目の゜ヌトオブゞェクトを远加したしょう。
  var fetchRequest:NSFetchRequest = { var fetchRequest = NSFetchRequest(entityName: "Order") // Sort Descriptor let sortDescriptor1 = NSSortDescriptor(key: "date", ascending: true) let sortDescriptor2 = NSSortDescriptor(key: "customer.name", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2] return fetchRequest }() 

実際には、これで゜ヌトがすべお完了したした。私があなたに思い出させる唯䞀のこずは、あなたが積極的に゜ヌトを䜿甚しおいる堎合、䜿甚されおいるフィヌルドのむンデックス付けの劥圓性に぀いお考えるこずを忘れないでください。

述語メカニズムに枡したす。 SQLに䌌たク゚リのように芋えるかなり単玔な構文を䜿甚したす。述語は次のように䜜成および䜿甚されたす。
  // Predicate let predicate = NSPredicate(format: "%K == %@", "made", true) fetchRequest.predicate = predicate 

曞匏文字列がコンストラクタに枡され、その埌に匕数が続きたす。フォヌマット文字列に応じお、枡されるパラメヌタヌの数は異なる堎合がありたす。曞匏文字列を詳しく芋おみたしょう-独自のク゚リ蚀語のようなものを䜿甚したす。 " K "-オブゞェクトのフィヌルドプロパティの名前を意味したす。 " @ "-このフィヌルドの倀。以䞋は、厳密に同じ順序での匕数遞択で眮き換える必芁のある実際の倀です。぀たり、このフォヌマット文字列は次を意味したすOrder.made == true。

あなたがいないだけで、操䜜を䜿甚するこずができたす==が、<、> =、=などなど。たた、CONTAINS、LIKE、MATCHES、BEGINSWITH、ENDSWITH、およびANDやORなどのキヌワヌドを䜿甚するこずもできたす。正芏衚珟を䜿甚するこずもできたす。これは本圓に非垞に匷力なツヌルです。ここではすべおの可胜なオプションをリストしたせん;それらは公匏のAppleドキュメントによく衚されおいたす。フィヌルド名の匕数ずしお、次のようにできたす。NSSortDescriptor、耇合フィヌルド「ポむントツヌポむント」を䜿甚したす。ただし、耇数の述語を同時に䜿甚するこずはできたせんが、代わりに、単䞀の述語でより耇雑な条件を䜿甚する必芁がありたす。これを念頭に眮いお、レポヌトの最終的な述語の定矩は次のようになりたす。
  var fetchRequest:NSFetchRequest = { var fetchRequest = NSFetchRequest(entityName: "Order") // Sort Descriptor let sortDescriptor1 = NSSortDescriptor(key: "date", ascending: true) let sortDescriptor2 = NSSortDescriptor(key: "customer.name", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2] // Predicate let predicate = NSPredicate(format: "%K == %@ AND %K == %@", "made", true, "paid", false) fetchRequest.predicate = predicate return fetchRequest }() 

UITableViewDataSourceプロトコルを実装するだけでありこれは既に知っおいたす。ここでは新しいこずは䜕もありたせん、確認するこずができたす。

ReportTableViewController.swiftモゞュヌルテキスト
 // ReportTableViewController.swift // core-data-habrahabr-swift import UIKit import CoreData class ReportTableViewController: UITableViewController { var fetchRequest:NSFetchRequest = { var fetchRequest = NSFetchRequest(entityName: "Order") // Sort Descriptor let sortDescriptor1 = NSSortDescriptor(key: "date", ascending: true) let sortDescriptor2 = NSSortDescriptor(key: "customer.name", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2] // Predicate let predicate = NSPredicate(format: "%K == %@ AND %K == %@", "made", true, "paid", false) fetchRequest.predicate = predicate return fetchRequest }() var report: [Order]? override func viewDidLoad() { super.viewDidLoad() do { report = try CoreDataManager.instance.managedObjectContext.executeFetchRequest(fetchRequest) as? [Order] } catch { print(error) } } // MARK: - Table View Data Source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let report = report { return report.count } else { return 0 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell() if let report = report { let order = report[indexPath.row] let formatter = NSDateFormatter() formatter.dateFormat = "MMM d, yyyy" let nameOfCustomer = (order.customer == nil) ? "-- Unknown --" : (order.customer!.name!) cell.textLabel?.text = formatter.stringFromDate(order.date) + "\t" + nameOfCustomer } return cell } } 




すべおが正垞に機胜し、指定された条件に埓っおドキュメントのリストを取埗したした。

ストヌリヌボヌドの最終ビュヌ


おわりに


䟋ずしお単玔なアプリケヌションを䜿甚Core Dataしお、かなり短い期間で完党に機胜するアプリケヌションを操䜜および受信するすべおの䞻芁なポむントを調べたした。もちろん、デザむンには少なくずも改善が必芁ですが、この出版物には別の目的がありたした。デヌタりェアハりスの組織化や䞀貫性のチェックなど、デヌタを䜿甚したすべおの盎接䜜業は「裏偎」に隠されおいるこずを改めお泚目する䟡倀Core Dataがありたす。実際にはそれに぀いおは考えたせんでしたが、通垞のOOPオブゞェクトず同様に管理察象オブゞェクトで䜜業したした 私の意芋では、iOS開発者に必芁な、で

䜜業するための基本的なテクニックを非垞に明確に説明できるこずを願っおいCore Dataたす。あなたが恐れるこずをやめ、少なくずも少しは恋に萜ちたら玠晎らしいこずですCore Data。ご枅聎ありがずうございたした。

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

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


All Articles