Indonesian (Bahasa Indonesia) translation by Imam Firmansyah (you can also view the original English article)
Di tutorial sebelumnya, kita sudah membuat fungsi untuk menambah, meng-update, dan menghapus ke daftar belanja. Sebuah daftar belanja tanpa barang di dalamnya tidak akan berguna. Dalam tutorial ini, kita akan membuat fungsi untuk menambahkan, meng-update, dan menghapus barang dari daftar belanja. Ini berarti kita akan menggunakan references dan class CKReference
.
Kita juga akan mempelajari lebih dalam tentang model data dari aplikasi daftar belanja. Seberapa mudah merubah model data dan bagaimana aplikasi merespons perubahan yang kita buat di CloudKit Dashboard?
Syarat Sebelum Memulai
Perlu diingat bahwa saya akan menggunakan Xcode 7 dan Swift 2. Jika Anda menggunakan Xcode versi lama, maka Anda harus menggunakan versi Swift yang berbeda.
Dalam tutorial ini, kita akan melanjutkan apa yang sudah kita kerjakan di tutorial kedua dari rangkaian tutorial ini. Anda bisa download atau clone proyek ini di GitHub.
1. Detail Daftar Belanja
Saat ini, user dapat mengubah nama daftar belanja dengan menekan detail disclosure indicator, tapi user juga harus dapat melihat barang belanjaan dengan menekan salah satu view controller. Untuk membuat ini bekerja, kita perlu subclass UIViewController
baru.
Langkah 1: Membuat ListViewController
Class ListViewController
akan menampilkan isi daftar belanja dalam bentuk tabel. Tampilan dari class ListViewController
terlihat mirip dengan class ListsViewController
. Kita akan mengimpor framework CloudKit dan SVProgressHUDkemudian menyesuaikan class ke protocol UITableViewDataSource
dan UITableViewDelegate
. Karena kita akan menggunakan table view, kita harus mendeklarasikan konstanta, ItemCell
, yang akan berfungsi sebagai identifier saat menggunakan ulang sel yang sama.
import UIKit import CloudKit import SVProgressHUD class ListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { static let ItemCell = "ItemCell" @IBOutlet weak var messageLabel: UILabel! @IBOutlet weak var tableView: UITableView! @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView! var list: CKRecord! var items = [CKRecord]() var selection: Int? ... }
Kita mendeklarasikan tiga outlet, messageLabel
dari tipe UILabel!
, tableView
dari tipe UITableView!
, and activityIndicatorView
dari tipe UIActivityIndicatorView!
. List view controller menyimpan referensi ke daftar belanja yang ditampilkan di properti list
, yang bertipe CKRecord!
. Item dalam daftar belanja disimpan di properti items
, yang bertipe [CKRecord]
. Akhirnya, kita menggunakan variable pembantu, selection
, untuk melacak dimana item dalam daftar belanja yang sudah dipilih user. Hal ini akan dibahas lebih jelas dalam tutorial ini.
Langkah 2: Membuat User Interface
Buka Main.storyboard, tambahkan view controller, dan atur class menjadi ListViewController
di Identity Inspector. Pilih prototype cell dari list view controller, tekan tombol kontrol, dan angkat prototype cell ke list view controller. Pilih Show dari menu yang muncul dan atur identifier menjadi List di Attributes Inspector.
Tambahkan table view, label, dan activity indicator view ke dalam view controller-nya view. Jangan lupa untuk memasang outlet pada view controller serta table view.
Pilih table view dan atur Prototype Cells menjadi 1 di Attributes Inspector. Pilh prototype cell, atur Style menjadi Right Detail, Identifier menjadi ItemCell, dan Accessory menjadi Disclosure Indicator. Seperti inilah tampilan view controller jika sudah selesai.

Langkah 3: Mengkonfigurasi View Controller
Sebelum kita membahas CloudKit framework, kita perlu menyiapkan view controller untuk data yang akan diterima. Dimulai dengan merubah implementasi dari viewDidLoad
. Kita mengatur judul dari view controller menjadi nama dari daftar belanja dan menjalankan dua method pembantu, setupView
dan fetchItems
.
// MARK: - // MARK: View Life Cycle override func viewDidLoad() { super.viewDidLoad() // Set Title title = list.objectForKey("name") as? String setupView() fetchItems() }
Method setupView
identik dengan yang kita terapkan dalam class ListsViewController
.
// MARK: - // MARK: View Methods private func setupView() { tableView.hidden = true messageLabel.hidden = true activityIndicatorView.startAnimating() }
Nah selanjutnya, mari kita implementasikan method pembantu lainnya, updateView
. Dalam updateView
, kita dapat merubah user interface dari view controller berdasarkan item yang disimpan dalam properti items
.
private func updateView() { let hasRecords = items.count > 0 tableView.hidden = !hasRecords messageLabel.hidden = hasRecords activityIndicatorView.stopAnimating() }
Untuk saat ini, saya akan tinggalkan fetchItems
dalam keadaan kosong. Kita akan meninjau kembalil method ini setelah selesai menyiapkan list view controller.
// MARK: - // MARK: Helper Methods private func fetchItems() { }
Langkah 4: Method Table View Data Source
Aplikasi kita hampir siap di tes. Sebelum melakukannya, kita perlu mengimplementasikan protocol UITableViewDataSource
. Jika Anda sudah membaca tutorial sebelumnya, maka hal ini tidak akan terlihat asing.
// MARK: - // MARK: Table View Data Source Methods func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1; } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // Dequeue Reusable Cell let cell = tableView.dequeueReusableCellWithIdentifier(ListViewController.ItemCell, forIndexPath: indexPath) // Configure Cell cell.accessoryType = .DetailDisclosureButton // Fetch Record let item = items[indexPath.row] if let itemName = item.objectForKey("name") as? String { // Configure Cell cell.textLabel?.text = itemName } else { cell.textLabel?.text = "-" } return cell } func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true }
Langkah 5: Menangani Selection
Untuk menggabungkan semuanya menjadi satu, kita harus menggunakan kembali class ListsViewController
. Mulai dengan menerapkan method tableView(_:didSelectRowAtIndexPath:)
dari protocol UITableViewDelegate
.
// MARK: - // MARK: Table View Delegate Methods func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) }
Kita juga perlu merubah prepareForSegue(segue:sender:)
untuk menangani segue yang kita buat beberapa saat yang lalu. Hal ini berarti bahwa kita perlu menambahkan case
baru ke dalam statement switch
.
// MARK: - // MARK: Segue Life Cycle override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { guard let identifier = segue.identifier else { return } switch identifier { case SegueList: // Fetch Destination View Controller let listViewController = segue.destinationViewController as! ListViewController // Fetch Selection let list = lists[tableView.indexPathForSelectedRow!.row] // Configure View Controller listViewController.list = list case SegueListDetail: ... default: break } }
Untuk memuaskan compiler, kita juga perlu mendeklarasikan konstanta SegueList
di bagian atas dari ListsViewController.swift.
import UIKit import CloudKit import SVProgressHUD let RecordTypeLists = "Lists" let SegueList = "List" let SegueListDetail = "ListDetail" class ListsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, AddListViewControllerDelegate { ... }
Buat dan jalankan aplikasi untuk melihat apakah semuanya terhubung dengan benar. Karena kita belum menerapkan method fetchItems
, jadi tidak ada item yang akan ditampilkan. Sehingga harus kita perbaiki.
2. Fetching Items
Langkah 1: Membuat Record Type
Sebelum kita mengambil item dari backend CloudKit, kita perlu membuat record type baru di CloudKit Dashboard. Arahkan ke CloudKit Dashboard, buat record type baru, dan beri nama Items. Setiap item harus memiliki nama jadi buatlah field baru, beri nama field tersebut name dan atur field type menjadi String.
Setiap item harus tahu menjadi milik daftar belanja yang mana. Hal ini berarti setiap item membutuhkan relasi ke daftar belanjanya. Buatlah field baru, dan beri nama field tersebut list dan atur field type menjadi Reference. Field dengan tipe Reference memiliki kegunaan untuk mengelola hubungan.

Kembali ke Xcode, buka ListsViewController.swift, dan deklarasikan konstanta baru di bagian atas dari record type Items.
import UIKit import CloudKit import SVProgressHUD let RecordTypeLists = "Lists" let RecordTypeItems = "Items" let SegueList = "List" let SegueListDetail = "ListDetail" class ListsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, AddListViewControllerDelegate { ... }
Langkah 2: Fetching Items
Buka ListViewController.swift dan arahkan ke method fetchItems
. Implementasinya hampir mirip dengan method fetchLists
dari class ListsViewController
. Namun ada beberapa perbedaan penting.
private func fetchItems() { // Fetch Private Database let privateDatabase = CKContainer.defaultContainer().privateCloudDatabase // Initialize Query let reference = CKReference(recordID: list.recordID, action: .DeleteSelf) let query = CKQuery(recordType: RecordTypeItems, predicate: NSPredicate(format: "list == %@", reference)) // Configure Query query.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)] // Perform Query privateDatabase.performQuery(query, inZoneWithID: nil) { (records, error) -> Void in dispatch_async(dispatch_get_main_queue(), { () -> Void in // Process Response on Main Thread self.processResponseForQuery(records, error: error) }) } }
Perbedaan penting antara fetchItems
dan fetchLists
adalah predicate yang kita berikan kepada CKQuery
initializer. Kita tidak perlu memperhatikan apa saja item yang ada di dalam database privat user. Kita hanya perlu memperhatikan item yang memiliki hubungan dengan daftar belanja tertentu. Hal ini terlihat dalam predicate dari contoh CKQuery
.
Kita membuat predicate dengan meneruskan instance CKReference
, yang kita buat dengan menerapkan init(recordID:action:)
. Method ini menerima dua argument, yaitu instance CKRecordID
yang merujuk pada record daftar belanja dan instance CKReferenceAction
yang menentukan apa yang terjadi ketika daftar belanja dihapus.
Reference actions sangat mirip dengan ketika kita menghapus aturan di Core Data. Jika object yang memiliki reference, dalam contoh ini adalah daftar belanja, dihapus, maka CloudKit framework akan memeriksa reference action untuk menentukan apa yang harus dilakukan pada record yang memiliki hubungan dengan record yang dihapus. Enum CKReferenceAction
memiliki dua values:
-
None
: Jika refrence dihapus, tidak akan terjadi apa-apa dengan record yang memiliki reference dengan record yang dihapus. -
DeleteSelf
: Jika reference dihapus, setiap record yang memiliki hubungan dengan record yang dihapus juga akan dihapus.
Karena tidak ada item di dalam daftar belanjaan, kita pilih reference action menjadi DeleteSelf
.
Method processResponseForQuery(records:error:)
tidak memiliki hal baru. Kita memproses respons dari query dan merubah user interface yang sesuai.
private func processResponseForQuery(records: [CKRecord]?, error: NSError?) { var message = "" if let error = error { print(error) message = "Error Fetching Items for List" } else if let records = records { items = records if items.count == 0 { message = "No Items Found" } } else { message = "No Items Found" } if message.isEmpty { tableView.reloadData() } else { messageLabel.text = message } updateView() }
Lakukan proses Build dan jalankan aplikasi. Anda tidak akan melihat item apa pun, tetapi user interface harus ter-update dan menunjukkan bahwa daftar belanja kosong.
3. Menambahkan Item
Langkah 1: Membuat AddItemViewControler
Saatnya menambahkan kemampuan untuk menambahkan item ke dalam daftar belanja. Mulai dengan membuat subclass baru UIViewController
, AddItemViewController
. Tampilan dari view controller mirip dengan class AddListViewController
.
Di bagian atas, kita import framework CloudKit dan SVProgressHUD. Kita deklarasikan protocol AddItemViewControllerDelegate
, yang akan memiliki tujuan yang sama dengan protocol AddListViewControllerDelegate
. Protocol ini mendefinisikan dua method, satu untuk menambahkan item dan satu lagi untuk meng-update item.
import UIKit import CloudKit import SVProgressHUD protocol AddItemViewControllerDelegate { func controller(controller: AddItemViewController, didAddItem item: CKRecord) func controller(controller: AddItemViewController, didUpdateItem item: CKRecord) } class AddItemViewController: UIViewController { @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var saveButton: UIBarButtonItem! var delegate: AddItemViewControllerDelegate? var newItem: Bool = true var list: CKRecord! var item: CKRecord? ... }
Kita mendeklarasikan dua outlet, yaitu text field dan bar button. Kita juga mendeklarasikan properti untuk delegate dan variable pembantu, newItem
, yang akan membantu kita untuk menentukan apakah kita harus membuat item baru atau meng-update item yang ada. Akhirnya, kita mendeklarasikan properti list
untuk menghubungkan daftar belanja dengan item yang akan ditambahkan dan properti item
untuk item yang akan kita buat atau update.
Sebelum kita membuat user interface, mari kita implementasikan dua action yang kita perlukan di storyboard, cancel(_:)
dan save(_:)
. Kita akan merubah implementasi dari action save(_:)
nanti di tutorial ini.
// MARK: - // MARK: Actions @IBAction func cancel(sender: AnyObject) { navigationController?.popViewControllerAnimated(true) } @IBAction func save(sender: AnyObject) { navigationController?.popViewControllerAnimated(true) }
Langkah 2: Membuat User Interface
Buka Main.storyboard, tambahkan bar button ke navigation bar dalam list view controller, dan atur System Item menjadi Add di Attributes Inspector. Masukkan view controller dari Object Library dan atur class menjadi AddItemViewController. Buat segue dari bar button yang baru saja kita buat di add item view controller. Pilih Show dari menu yang tampil dan atur identifier segue menjadi ItemDetail.
Tambahkan dua bar button ke navigation bar dari add item view controller, cancel button di sebelah kiri dan save button di sebelah kanan. Hubungkan setiap bar button ke action yang sesuai. Tambahkan text field ke tampilan view controller dan jangan lupa untuk menghubungkan outlet dari view controller. Berikut tampilan dari add item view controller jika sudah selesai.

Langkah 3: Mengkonfigurasi View Controller
Implementasi dari add item view controller belum kita bahas. Ada satu pengecualian, yang akan kita bahas sebentar lagi. Mari kita mulai dengan mengkonfigurasi view controller di viewDidLoad
.
Kita memanggil setupView
, sebuah method pembantu, dan merubah nilai dari newItem
. Jika properti item
sama dengan nil
, maka newItem
sama dengan true
. Hal ini membantu kita menentukan item mana yang harus dibuat dan di-update dalam daftar belanja.
Kita juga menambahkan view controller untuk mengamati notifikasi dari tipe UITextFieldTextDidChangeNotification
. Ini berarti view controller akan diberitahu ketika isi dari nameTextField
berubah.
// MARK: - // MARK: View Life Cycle override func viewDidLoad() { super.viewDidLoad() setupView() // Update Helper newItem = item == nil // Add Observer let notificationCenter = NSNotificationCenter.defaultCenter() notificationCenter.addObserver(self, selector: "textFieldTextDidChange:", name: UITextFieldTextDidChangeNotification, object: nameTextField) }
Dalam viewDidAppear(animated:)
, kita menampilkan keyboard dengan memanggil becomeFirstResponder
pada nameTextField
.
override func viewDidAppear(animated: Bool) { nameTextField.becomeFirstResponder() }
Method setupView
memanggil dua method pembantu, updateNameTextField
dan updateSaveButton
. Implementasi dari dua method pembantu ini sangat mudah. Di updateNameTextField
, kita mengisi text field. Di updateSaveButton
, kita bisa mengaktifkan atau menonaktifkan save button tergantung pada isi dari text field.
// MARK: - // MARK: View Methods private func setupView() { updateNameTextField() updateSaveButton() } // MARK: - private func updateNameTextField() { if let name = item?.objectForKey("name") as? String { nameTextField.text = name } } // MARK: - private func updateSaveButton() { let text = nameTextField.text if let name = text { saveButton.enabled = !name.isEmpty } else { saveButton.enabled = false } }
Sebelum kita bahas implementasi dari method save(_:)
, kita perlu mengimplementasikan method textFieldDidChange(_:)
. Hal yang perlu dilakukan adalah memanggil updateSaveButton
untuk mengaktifkan atau menonaktifkan save button.
// MARK: - // MARK: Notification Handling func textFieldTextDidChange(notification: NSNotification) { updateSaveButton() }
Langkah 4: Menyimpan Item
Method save(_:)
adalah method yang paling menarik dari class AddItemViewController
, karena method ini menunjukkan bagaimana kita berhubungan dengan CloudKit. Coba perhatikan implementasi method save(_:)
di bawah ini.
Sebagian besar implementasinya harus terlihat sama karena kita mau menyimpan record di class AddListViewController
. Yang paling menarik adalah cara item tersebut menyimpan referensi ke dalam daftar belanjanya. Pertama-tama kita membuat instance CKReference
dengan menjalankan initializer yang ditentukan, init(recordID:action:)
. Kemudian bungkus detailnya dengan membuat instance CKReference
yang sudah kita buat beberapa sebelumnya saat kita membuat query untuk fetching item dari daftar belanja.
Cara memberitahu item tentang refrensi ini mudah. Kita cukup memanggil setObjec(_:forKey:)
pada properti item
, lalu meneruskan instance CKReference
sebagai value dan "list"
sebagai kuncinya. Kunci tersebut sesuai dengan nama field yang sudah ditetapkan di CloudKit Dashboard. Menyimpan item tersebut ke iCloud sudah identik dengan apa yang kita lakukan sebelumnya. Itulah cara mudah untuk menggunakan CloudKit references.
@IBAction func save(sender: AnyObject) { // Helpers let name = nameTextField.text // Fetch Private Database let privateDatabase = CKContainer.defaultContainer().privateCloudDatabase if item == nil { // Create Record item = CKRecord(recordType: RecordTypeItems) // Initialize Reference let listReference = CKReference(recordID: list.recordID, action: .DeleteSelf) // Configure Record item?.setObject(listReference, forKey: "list") } // Configure Record item?.setObject(name, forKey: "name") // Show Progress HUD SVProgressHUD.show() // Save Record privateDatabase.saveRecord(item!) { (record, error) -> Void in dispatch_async(dispatch_get_main_queue(), { () -> Void in // Dismiss Progress HUD SVProgressHUD.dismiss() // Process Response self.processResponse(record, error: error) }) } }
Implementasi dari processResponse(record:error:)
bukanlah hal baru. Kita memeriksa jika ada eror yang muncul dan, jika tidak ada eror yang ditemukan, kita akan memberitahu delegate.
// MARK: - // MARK: Helper Methods private func processResponse(record: CKRecord?, error: NSError?) { var message = "" if let error = error { print(error) message = "We were not able to save your item." } else if record == nil { message = "We were not able to save your item." } if !message.isEmpty { // Initialize Alert Controller let alertController = UIAlertController(title: "Error", message: message, preferredStyle: .Alert) // Present Alert Controller presentViewController(alertController, animated: true, completion: nil) } else { // Notify Delegate if newItem { delegate?.controller(self, didAddItem: item!) } else { delegate?.controller(self, didUpdateItem: item!) } // Pop View Controller navigationController?.popViewControllerAnimated(true) } }
Langkah 5: Meng-update ListViewController
Kita masih memiliki beberapa hal yang harus dikerjakan di class ListViewController
. Dimulai dari menyesuaikan class ListViewController
ke protocol AddItemViewControllerDelegate
. Ini juga merupakan momen yang bagus untuk mendeklarasikan konstanta untuk segue dengan identifier ItemDetail.
import UIKit import CloudKit import SVProgressHUD let SegueItemDetail = "ItemDetail" class ListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, AddItemViewControllerDelegate { ... }
Mengimplementasikan protocol AddItemViewControllerDelegate
adalah hal yang sepele. Dalam controller(_:didAddItem:)
, kita menambahkan item baru ke dalam item items
, mengurutkan items
, me-reload table view, dan menjalankan updateView
.
// MARK: - // MARK: Add Item View Controller Delegate Methods func controller(controller: AddItemViewController, didAddItem item: CKRecord) { // Add Item to Items items.append(item) // Sort Items sortItems() // Update Table View tableView.reloadData() // Update View updateView() }
Implementasi dari controller(_:didUpdateItem:)
bahkan lebih mudah. Kita hanya mengurutkan items
dan me-reload table view.
func controller(controller: AddItemViewController, didUpdateItem item: CKRecord) { // Sort Items sortItems() // Update Table View tableView.reloadData() }
Dalam sortItems
, kita mengurutkan array dari instance CKRecord
berdasarkan nama yang menggunakan function sortInPlace
, yang merupakan method dari protocol MutableCollectionType
.
private func sortItems() { items.sortInPlace { var result = false let name0 = $0.objectForKey("name") as? String let name1 = $1.objectForKey("name") as? String if let itemName0 = name0, itemName1 = name1 { result = itemName0.localizedCaseInsensitiveCompare(itemName1) == .OrderedAscending } return result } }
Ada dua fitur lagi yang harus kita terapkan, yaitu meng-update dan menghapus item daftar belanja.
Langkah 6: Menghapus Item
Untuk menghapus item, kita perlu mengimplementasikan tableView(_:commitEditingStyle:forRowAtIndexPath:)
dari protocol UITableViewDataSource
. Kita harus mengambil item dari daftar belanja yang akan dihapus dan melemparnya ke method deleteRecord(_:)
.
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { guard editingStyle == .Delete else { return } // Fetch Record let item = items[indexPath.row] // Delete Record deleteRecord(item) }
Implementasi dari deleteRecord(_:)
bukanlah hal yang baru. Kita menjalankan deleteRecordWithID(_:completionHandler:)
pada private database dan memproses respon dalam completion handler.
private func deleteRecord(item: CKRecord) { // Fetch Private Database let privateDatabase = CKContainer.defaultContainer().privateCloudDatabase // Show Progress HUD SVProgressHUD.show() // Delete List privateDatabase.deleteRecordWithID(item.recordID) { (recordID, error) -> Void in dispatch_async(dispatch_get_main_queue(), { () -> Void in // Dismiss Progress HUD SVProgressHUD.dismiss() // Process Response self.processResponseForDeleteRequest(item, recordID: recordID, error: error) }) } }
Dalam processResponseForDeleteRequest(record:recordID:error:)
, kita merubah properti items
dan juga user interface. Jika ada yang salah, kita beritahu user dengan menampilkan peringatan.
private func processResponseForDeleteRequest(record: CKRecord, recordID: CKRecordID?, error: NSError?) { var message = "" if let error = error { print(error) message = "We are unable to delete the item." } else if recordID == nil { message = "We are unable to delete the item." } if message.isEmpty { // Calculate Row Index let index = items.indexOf(record) if let index = index { // Update Data Source items.removeAtIndex(index) if items.count > 0 { // Update Table View tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: .Right) } else { // Update Message Label messageLabel.text = "No Items Found" // Update View updateView() } } } else { // Initialize Alert Controller let alertController = UIAlertController(title: "Error", message: message, preferredStyle: .Alert) // Present Alert Controller presentViewController(alertController, animated: true, completion: nil) } }
Langkah 7: Meng-update Item
User dapat meng-update item dengan menekan detail disclosure indicator. Ini berarti kita perlu menerapkan method delegate tableView(_:accessoryButtonTappedForRowWithIndexPath:)
. Dalam method ini, kita menyimpan pilihan user dan secara manual memanggil segue ListDetail . Perlu diperhatikan bahwa tidak ada yang terjadi di method tableView(_:didSelectRowAtIndexPath:)
. Yang kita lakukan adalah menghapus baris yang dipilih oleh user.
// MARK: - // MARK: Table View Delegate Methods func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) } func tableView(tableView: UITableView, accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) // Save Selection selection = indexPath.row // Perform Segue performSegueWithIdentifier(SegueItemDetail, sender: self) }
Dalam prepareForSegue(_:sender:)
, kita mengambil item dari daftar belanja menggunakan value dari properti selection
dan mengkonfigurasi tujuan view controller, sebuah instance dari class AddItemViewController
.
// MARK: - // MARK: Segue Life Cycle override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { guard let identifier = segue.identifier else { return } switch identifier { case SegueItemDetail: // Fetch Destination View Controller let addItemViewController = segue.destinationViewController as! AddItemViewController // Configure View Controller addItemViewController.list = list addItemViewController.delegate = self if let selection = selection { // Fetch Item let item = items[selection] // Configure View Controller addItemViewController.item = item } default: break } }
Itulah hal yang kita lakukan untuk menghapus dan meng-update item dari daftar belanja. Di sesi berikutnya, kita akan membahas cara mudah untuk meng-update model data di CloudKit Dashboard.
4. Meng-update Model Data
Jika Anda pernah menggunakan Core Data sebelumnya, maka Anda pasti tahu kalau meng-update model data harus dilakukan dengan hati-hati. Anda perlu memastikan Anda tidak merusak apa pun atau merusak aplikasi toko yang sudah ada. Tenang, CloudKit sedikit lebih fleksibel.
Record dengan tipe Items saat ini memiliki dua field, yaitu name dan list. Saya ingin menunjukkan kepada Anda apa yang perlu dilakukan untuk meng-update model data dengan menambahkan field baru. Buka CloudKit Dashboard dan tambahkan field baru ke record Items. Beri nama field menjadi number dan pilih tipe field menjadi Int(64). Jangan lupa menyimpannya.

Sekarang mari kiya tambahkan kemampuan untuk memodifikasi nomor item. Buka AddItemViewController.swift dan deklarasikan dua outlet, label dan stepper.
import UIKit import CloudKit import SVProgressHUD protocol AddItemViewControllerDelegate { func controller(controller: AddItemViewController, didAddItem item: CKRecord) func controller(controller: AddItemViewController, didUpdateItem item: CKRecord) } class AddItemViewController: UIViewController { @IBOutlet weak var numberLabel: UILabel! @IBOutlet weak var numberStepper: UIStepper! @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var saveButton: UIBarButtonItem! var delegate: AddItemViewControllerDelegate? var newItem: Bool = true var list: CKRecord! var item: CKRecord? ... }
Kita juga perlu menambahkan action yang dapat ter-trigger jika value dari stepper berubah. Di numberDidChange(_:)
, kita meng-update isi dari numberLabel
.
@IBAction func numberDidChange(sender: UIStepper) { let number = Int(sender.value) // Update Number Label numberLabel.text = "\(number)" }
Buka Main.storyboard dan tambahkan label dan stepper ke add item view controller. Hubungkan outlet dari view controller ke elemen user interface yang sesuai dan hubungkan action numberDidChange(_:)
ke stepper untuk event Value Changed.

Action save(_:)
dari class AddItemViewController
juga berubah sedikit. Mari kita lihat seperti apa perubahannya.
Kita hanya perlu menambahkan dua baris code. Di bagian atas, kita menyimpan value dari stepper ke dalam konstanta, number
. Ketika kita mengkonfigurasi item
, kita menetapkan number
sebagai value untuk key "number"
.
@IBAction func save(sender: AnyObject) { // Helpers let name = nameTextField.text let number = Int(numberStepper.value) // Fetch Private Database let privateDatabase = CKContainer.defaultContainer().privateCloudDatabase if item == nil { // Create Record item = CKRecord(recordType: RecordTypeItems) // Initialize Reference let listReference = CKReference(recordID: list.recordID, action: .DeleteSelf) // Configure Record item?.setObject(listReference, forKey: "list") } // Configure Record item?.setObject(name, forKey: "name") item?.setObject(number, forKey: "number") // Show Progress HUD SVProgressHUD.show() print(item?.recordType) // Save Record privateDatabase.saveRecord(item!) { (record, error) -> Void in dispatch_async(dispatch_get_main_queue(), { () -> Void in // Dismiss Progress HUD SVProgressHUD.dismiss() // Process Response self.processResponse(record, error: error) }) } }
Kita juga perlu mengimplementasikan method pembantu untuk meng-update user interface dari add item view controller. Method updateNumberStepper
akan memeriksa apakah record memiliki field bernama number dan akan meng-update stepper jika iya.
private func updateNumberStepper() { if let number = item?.objectForKey("number") as? Double { numberStepper.value = number } }
Kita memanggil updateNumberStepper
di dalam method setupView
dari class AddItemViewController
.
private func setupView() { updateNameTextField() updateNumberStepper() updateSaveButton() }
Untuk menampilkan jumlah setiap item, kita perlu membuat satu perubahan di ListViewController
. Dalam tableView(_:cellForRowAtIndexPath:)
, kita mengisi value dari label yang benar ke nomor field item.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // Dequeue Reusable Cell let cell = tableView.dequeueReusableCellWithIdentifier(ListViewController.ItemCell, forIndexPath: indexPath) // Configure Cell cell.accessoryType = .DetailDisclosureButton // Fetch Record let item = items[indexPath.row] if let itemName = item.objectForKey("name") as? String { // Configure Cell cell.textLabel?.text = itemName } else { cell.textLabel?.text = "-" } if let itemNumber = item.objectForKey("number") as? Int { // Configure Cell cell.detailTextLabel?.text = "\(itemNumber)" } else { cell.detailTextLabel?.text = "1" } return cell }
Itulah yang perlu kita lakukan untuk meng-update model data. Tidak perlu melakukan migrasi atau hal lain. CloudKit dapat menanganinya dengan detail.
Kesimpulan
Anda sekarang sudah punya dasar pemahaman tentang CloudKit framework. Saya harap Anda setuju bahwa Apple telah melakukan hal hebat dengan framework dan CloudKit Dashboard. Masih ada banyak hal yang belum kita bahas dalam serial ini, tapi ini seharusnya sudah cukup untuk memacu Anda untuk mulai menggunakan CloudKit dalam proyek Anda.
Jika Anda memiliki pertanyaan atau komentar, silahkan tinggalkan komentar di bawah atau hubungi saya di Twitter
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post