iOS
...
Data Objects
Basic Operations
17 min
crud parse objects in ios introduction storing data on parse is built around the parse object parse object class each parse object parse object contains key value pairs of json compatible data this data is schemaless, which means that you don’t need to specify ahead of time what keys exist on each parse object parse object you can simply set whatever key value pairs you want, and our backend will store it you can also specify the datatypes according to your application needs and persist types such as number number , boolean boolean , string string , datetime datetime , list list , geopointers geopointers , and object object , encoding them to json before saving parse also supports store and query relational data by using the types pointers pointers and relations relations in this guide, you will learn how to perform basic data operations through a crud example app (todo list app), which will show you how to create, read, update and delete data from your parse server database using the parseswift sdk parseswift sdk this tutorial uses a basic app created in xcode 12 and ios 14 at any time, you can access the complete project via our github repositories ios example repository goal to learn how to perform basic database operations on back4app using a todo list app as an example prerequisites to complete this quickstart, you need xcode an app created at back4app follow the new parse app tutorial to learn how to create a parse app at back4app note follow the install parse sdk (swift) tutorial to create an xcode project connected to back4app understanding our to do list app to better understand the parseswift sdk parseswift sdk you will perform crud operations on a to do list app the application database will have a simple task class with a title and a description (both strings strings ) you can update each task’s title and/or description quick reference of commands we are going to use once an object conforms the parseswift parseswift protocol, it automatically implements a set of methods that will allow you to manage the object and update any changes on your back4app database given the object todolistitem todolistitem 1 struct todolistitem parseobject { 2 3 4 /// title for the todo item 5 var title string? 6 7 /// description for the todo item 8 var description string? 9 } these methods are listed below create //once created an instance of todolistitem object and set its custom properties, you can save it on your back4app database by calling any of the following methods 1 var newitem todoilisttem 2 // newitem's properties 3 4 // saves newitem on your back4app database synchronously and returns the new saved item it throws and error if something went wrong 5 let saveditem = try? newitem save() 6 7 // saves newitem on your back4app database asynchronously, and passes a result\<todolistitem, parseerror> object to the completion block to handle the save proccess 8 newitem save { result in 9 // handle the result to check the save was successfull or not 10 } 11 read //for reading objects stored on your back4app database, todolistitem now provides the query() static method which returns a query\<todolistitem> this query object can be constructed using on or more queryconstraint objects int he following way 1 let query = todolistitem query() // a query to fetch all todolistitem items on your back4app database 2 let query = todolistitem query("title" == "some title") // a query to fetch all todolistitem items with title "some title" on your back4app database 3 let query = todolistitem query(\["title" == "some title", "description" = "ok"]) // a query to fetch all todolistitem items with title = "some title" and description = "ok" 4 5 // fetchs the items synchronously or throws an error if found 6 let fetcheditems = try? query find() 7 8 // fetchs the items asynchronously and calls a completion block passing a result object containing the result of the operation 9 query find { result in 10 // handle the result 11 } update //given the objectid of an object stored on you back4app database, you can update it in the following way 1 let itemtoupdate = todolistitem(objectid "oobject id") 2 // update the properites of itemtoupdate 3 4 // save changes synchronousty 5 itemtoupdate save() 6 7 // or save changes asynchronously 8 itemtoupdate save { result in 9 // handle the result 10 } delete //the deletion process is performed by calling the method delete() on the object to be deleted 1 var itemtodelete todolistitem 2 3 // delete itemtodelete synchronously 4 try? itemtodelete delete() 5 6 // delte itemtodelete asynchronously 7 itemtodelete delete { result in 8 // handleresult 9 } 1 create to do list app template at any time, you can access the complete project via our github repositories ios example repository go to xcode, and find the scenedelegate swift scenedelegate swift file in order to add a navigation bar on top of the app, we setup a uinavigationcontroller uinavigationcontroller as the root view controller in the following way 1 class scenedelegate uiresponder, uiwindowscenedelegate { 2 3 var window uiwindow? 4 5 func scene( scene uiscene, willconnectto session uiscenesession, options connectionoptions uiscene connectionoptions) { 6 guard let scene = (scene as? uiwindowscene) else { return } 7 8 window = init(windowscene scene) 9 window? rootviewcontroller = uinavigationcontroller(rootviewcontroller todolistcontroller()) 10 window? makekeyandvisible() 11 12 // additional logic 13 } 14 15 16 } the root view controller class ( todolistcontroller todolistcontroller ) for the navigation controller is a subclass of uitableviewcontroller uitableviewcontroller , this makes easy to layout a list of items 2 setup the crud object objects you want to save on your back4app database have to conform the parseobject parseobject protocol on our to do liat app this object is todolistitem todolistitem therefore, you first need to create this object 1 import foundation 2 import parseswift 3 4 struct todolistitem parseobject { 5 // required properties from parseobject protocol 6 var objectid string? 7 var createdat date? 8 var updatedat date? 9 var acl parseacl? 10 11 /// title for the todo item 12 var title string? 13 14 /// description for the todo item 15 var description string? 16 } this object defines a class in your back4app database any new instance of this object is then stored in your database under the todolistitem todolistitem class 3 setup todolistcontroller in todolistcontroller todolistcontroller we should implement all the necessary configuration for the navigationbar navigationbar , and tableview tableview properties 1 class todolistcontroller uitableviewcontroller { 2 var items \[todolistitem] = \[] 3 4 override func viewdidload() { 5 super viewdidload() 6 7 setuptableview() 8 setupnavigationbar() 9 } 10 11 private func setupnavigationbar() { 12 navigationitem title = "to do list" uppercased() 13 navigationitem rightbarbuttonitem = uibarbuttonitem(barbuttonsystemitem add, target self, action #selector(handlenewitem)) 14 } 15 16 private func setuptableview() { 17 tableview\ register(todolistitemcell self, forcellreuseidentifier todolistitemcell identifier) 18 } 19 20 override func tableview( tableview uitableview, numberofrowsinsection section int) > int { 21 items count 22 } 23 24 override func tableview( tableview uitableview, cellforrowat indexpath indexpath) > uitableviewcell { 25 let cell = tableview\ dequeuereusablecell(withidentifier todolistitemcell identifier, for indexpath) as! todolistitemcell 26 cell item = items\[indexpath row] 27 return cell 28 } 29 30 /// this method is called when the user wants to add a new item to the to do list 31 @objc private func handlenewitem() { 32 33 } 34 35 36 } to conclude this step, we implement the custom table view cell todolistitemcell todolistitemcell 1 // content of todolistitemcell swift file 2 class todolistitemcell uitableviewcell { 3 class var identifier string { "\\(nsstringfromclass(self self)) identifier" } // cell's identifier 4 5 /// when set, it updates the title and detail texts of the cell 6 var item todolistitem? { 7 didset { 8 textlabel? text = item? title 9 detailtextlabel? text = item? description 10 } 11 } 12 13 override init(style uitableviewcell cellstyle, reuseidentifier string?) { 14 super init(style subtitle, reuseidentifier reuseidentifier) 15 16 accessorytype = detailbutton // this accessory button will be used to present edit options for the item 17 } 18 19 required init?(coder nscoder) { 20 super init(coder coder) 21 22 accessorytype = detailbutton // this accessory button will be used to present edit options for the item 23 } 24 } 4 crud flow we implement all crud logic in the todolistcontroller todolistcontroller class go to todolistcontroller swift todolistcontroller swift and add the following methods to the todolistcontroller todolistcontroller class 1 // mark crud flow 2 extension todolistcontroller { 3 /// creates a todolistitem and stores it on your back4app database 4 /// parameters 5 /// title the title for the to do task 6 /// description an optional description for the to to task 7 func createobject(title string, description string?) { 8 9 } 10 11 /// retrieves all the todolistitem objects from your back4app database 12 func readobjects() { 13 14 } 15 16 /// updates a todolistitem object on your back4app database 17 /// parameters 18 /// objectid the object id of the todolistitem to update 19 /// newtitle new title for the to to task 20 /// newdescription new description for the to do task 21 func updateobject(objectid string, newtitle string, newdescription string?) { 22 23 } 24 25 /// deletes a todolistitem on your back4app database 26 /// parameter item the item to be deleted on your back4app database 27 func deleteobject(item todolistitem) { 28 29 } 30 } \ create object now we start implementing the createobject(title\ description ) createobject(title\ description ) method create an instance of todolistitem todolistitem using the init(title\ description ) init(title\ description ) initializer in order to save this new item on your back4app database, the parseswift parseswift protocol provides a save() save() method this method can be called synchronously or asynchronously, choose one of them according to your use case an asynchrononous implementation should look like this 1 func createobject(title string, description string?) { 2 let item = todolistitem(title title, description description) 3 4 item save { \[weak self] result in 5 guard let self = self else { return } 6 switch result { 7 case success(let saveditem) 8 self items append(saveditem) 9 dispatchqueue main async { 10 self tableview\ insertrows(at \[indexpath(row self items count 1, section 0)], with right) 11 } 12 case failure(let error) 13 dispatchqueue main async { 14 self showalert(title "error", message "failed to save item \\(error message)") 15 } 16 } 17 } 18 } now we can complete the action for the add button located at the right side of the navigation bar go to todolistcontroller todolistcontroller and add the following 1 class todolistcontroller uitableviewcontroller { 2 enum itemdescription int { case title = 0, description = 1 } 3 4 5 6 /// this method is called when the user wants to add a new item to the to do list 7 @objc private func handlenewitem() { 8 showeditcontroller(item nil) 9 } 10 11 /// presents an alert where the user enters a to do task for either create a new one (item parameter is nil) or edit an existing one 12 private func showeditcontroller(item todolistitem?) { 13 let controllertitle string = item == nil ? "new item" "update item" 14 15 let edititemalertcontroller = uialertcontroller(title controllertitle, message nil, preferredstyle alert) 16 17 edititemalertcontroller addtextfield { textfield in 18 textfield tag = itemdescription title rawvalue 19 textfield placeholder = "title" 20 textfield text = item? title 21 } 22 23 edititemalertcontroller addtextfield { textfield in 24 textfield tag = itemdescription description rawvalue 25 textfield placeholder = "description" 26 textfield text = item? description 27 } 28 29 let mainactiontitle string = item == nil ? "add" "update" 30 31 let mainaction uialertaction = uialertaction(title mainactiontitle, style default) { \[weak self] in 32 guard let title = edititemalertcontroller textfields? first(where { $0 tag == itemdescription title rawvalue })? text else { 33 return edititemalertcontroller dismiss(animated true, completion nil) 34 } 35 36 let description = edititemalertcontroller textfields? first(where { $0 tag == itemdescription description rawvalue })? text 37 38 edititemalertcontroller dismiss(animated true) { 39 if let objectid = item? objectid { // if the item passed as parameter is not nil, the alert will update it 40 self? updateobject(objectid objectid, newtitle title, newdescription description) 41 } else { 42 self? createobject(title title, description description) 43 } 44 } 45 } 46 47 let cancelaction = uialertaction(title "cancel", style cancel, handler nil) 48 49 edititemalertcontroller addaction(mainaction) 50 edititemalertcontroller addaction(cancelaction) 51 52 present(edititemalertcontroller, animated true, completion nil) 53 } 54 } \ read object we move to the readobjects() readobjects() method retreiveing todolistitem todolistitem items from your back4app database is performed via a query\<todolistitem> query\<todolistitem> object this query is instanciated in the following way 1 func readobjects() { 2 let query = todolistitem query() 3 4 } in this tutorial we use a query which will retreive all the items of type todolistitem todolistitem from your back4app database in case you want to retreive a set of specific items, you can provide queryconstraint queryconstraint elements to todolistitem query(queryconstraint ) todolistitem query(queryconstraint ) for instance, to fetch all items where title == "some title" title == "some title" , the query takes the form 1 let query = todolistitem query("title" == "some title") once you have the query ready, we proceed to retreive the items by calling query find() query find() again, this can be done synchronously or asynchronously in our to do list app we implement it asynchronously 1 func readobjects() { 2 let query = todolistitem query() 3 4 query find { \[weak self] result in 5 guard let self = self else { return } 6 switch result { 7 case success(let items) 8 self items = items 9 dispatchqueue main async { 10 self tableview\ reloadsections(\[0], with top) 11 } 12 case failure(let error) 13 dispatchqueue main async { 14 self showalert(title "error", message "failed to save item \\(error message)") 15 } 16 } 17 } 18 } with readobjects() readobjects() completed, we can now fetch all the tasks stored in your back4app database and show them right after the app enters to foreground go back to todolistcontroller todolistcontroller and override the viewdidappear() viewdidappear() method 1 class todolistcontroller uitableviewcontroller { 2 3 4 override func viewdidappear( animated bool) { 5 super viewdidappear(animated) 6 7 readobjects() 8 } 9 10 11 } \ update object given the objectid objectid of a todolistitem todolistitem object, it is straightforward to perform an update we simply instanciate a todolistitem todolistitem object using the init(objectid ) init(objectid ) initializer next, we update the properties we need and call the save() save() method (of todolistitem todolistitem ) to save changes 1 func updateobject(objectid string, newtitle string, newdescription string?) { 2 var item = todolistitem(objectid objectid) 3 item title = newtitle 4 item description = newdescription 5 6 item save { \[weak self] result in 7 switch result { 8 case success 9 if let row = self? items firstindex(where { $0 objectid == item objectid }) { 10 self? items\[row] = item 11 dispatchqueue main async { 12 self? tableview\ reloadrows(at \[indexpath(row row, section 0)], with fade) 13 } 14 } 15 case failure(let error) 16 dispatchqueue main async { 17 self? showalert(title "error", message "failed to save item \\(error message)") 18 } 19 } 20 } 21 } \ delete object deleting objects on your back4app database is very similar to creating objects we begin by creating an instance of todolistitem todolistitem with the objectid of the item we want to delete next, we simply call (synchronously or ascynchronously) the delete() delete() method of the object if the deletion was successfull we update the ui, otherwise we report the error 1 func deleteobject(item todolistitem) { 2 item delete { \[weak self] result in 3 switch result { 4 case success 5 if let row = self? items firstindex(where { $0 objectid == item objectid }) { 6 self? items remove(at row) 7 dispatchqueue main async { 8 self? tableview\ deleterows(at \[indexpath(row row, section 0)], with left) 9 } 10 } 11 case failure(let error) 12 dispatchqueue main async { 13 self? showalert(title "error", message "failed to save item \\(error message)") 14 } 15 } 16 } 17 } with deleteobject(item ) deleteobject(item ) and updateobject(objectid\ newtitle\ newdescription) updateobject(objectid\ newtitle\ newdescription) completed, we proceed to add the corresponding actions to call these operations go back to todolistcontroller todolistcontroller and add 1 // mark uitableviewdatasource delegate 2 extension todolistcontroller { 3 // when the user taps on the accessory button of a cell, we present the edit options for the to do list task 4 override func tableview( tableview uitableview, accessorybuttontappedforrowwith indexpath indexpath) { 5 guard !items isempty else { return } 6 7 showeditoptions(item items\[indexpath row]) 8 } 9 10 /// presents a sheet where the user can select an action for the to do list item 11 private func showeditoptions(item todolistitem) { 12 let alertcontroller = uialertcontroller(title title, message nil, preferredstyle actionsheet) 13 14 let editaction = uialertaction(title "edit", style default) { \[weak self] in 15 self? showeditcontroller(item item) 16 } 17 18 let deleteaction = uialertaction(title "delete", style destructive) { \[weak self] in 19 alertcontroller dismiss(animated true) { 20 self? deleteobject(item item) 21 } 22 } 23 24 let cancelaction = uialertaction(title "cancel", style cancel) { in 25 alertcontroller dismiss(animated true, completion nil) 26 } 27 28 alertcontroller addaction(editaction) 29 alertcontroller addaction(deleteaction) 30 alertcontroller addaction(cancelaction) 31 32 present(alertcontroller, animated true, completion nil) 33 } 34 } as we pointed out earlier, the accessory button in each todolistitemcell todolistitemcell triggers an edit sheet via the tableview( accessorybuttontappedforrowwith ) tableview( accessorybuttontappedforrowwith ) delegate method it’s done! at this point, you have learned how to do the basic crud operations with parse on ios