{"id":211,"date":"2015-12-29T23:33:53","date_gmt":"2015-12-29T23:33:53","guid":{"rendered":"http:\/\/kevingoedecke.com\/?p=211"},"modified":"2016-01-07T14:48:10","modified_gmt":"2016-01-07T14:48:10","slug":"loopback-swift-example-crud-app","status":"publish","type":"post","link":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/","title":{"rendered":"LoopBack Swift Example CRUD App"},"content":{"rendered":"<h2>Key Features<\/h2>\n<ul>\n<li>Swift Example App accessing a LoopBack Backend providing basic Create, Read, Update and Delete operations<\/li>\n<li>Supports iOS 9, written in Swift 2<\/li>\n<li>Uses the official <a href=\"https:\/\/github.com\/strongloop\/loopback-sdk-ios\" target=\"_blank\">Loopback iOS SDK<\/a><\/li>\n<li>Source code includes LoopBack Server Test App<\/li>\n<\/ul>\n<h2>Source Code<\/h2>\n<p>Available on GitHub: <a href=\"https:\/\/github.com\/kgoedecke\/loopback-swift-crud-example\" target=\"_blank\">https:\/\/github.com\/kgoedecke\/loopback-swift-crud-example<\/a><\/p>\n<h2>Screenshots<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-214\" src=\"http:\/\/kevingoedecke.com\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-1@2x-593x1024.jpg\" alt=\"screenshot-loopback-swift-1@2x\" width=\"300\" height=\"518\" srcset=\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-1@2x-593x1024.jpg 593w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-1@2x-174x300.jpg 174w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-1@2x.jpg 750w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/> <img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-215\" src=\"http:\/\/kevingoedecke.com\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-2@2x-593x1024.jpg\" alt=\"screenshot-loopback-swift-2@2x\" width=\"300\" height=\"518\" srcset=\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-2@2x-593x1024.jpg 593w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-2@2x-174x300.jpg 174w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/screenshot-loopback-swift-2@2x.jpg 750w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<h2>Prerequisites<\/h2>\n<ul>\n<li>Deployed <a href=\"http:\/\/loopback.io\/\" target=\"_blank\">LoopBack<\/a> Test App available here:<br \/>\n<a href=\"https:\/\/github.com\/kgoedecke\/loopback-swift-crud-example\/tree\/master\/loopback-swift-crud-example-tests\/server\" target=\"_blank\">GitHub: kgoedecke\/loopback-swift-crud-example &#8211; LoopBack Server App<\/a><\/li>\n<li>Make the LoopBack iOS SDK available through Cocoapods as introduced here:<br \/>\n<a href=\"http:\/\/kevingoedecke.com\/2015\/12\/11\/using-loopback-ios-sdk-with-cocoapods-in-swift\/\" target=\"_blank\">Using LoopBack iOS SDK with Cocoapods in Swift<\/a><\/li>\n<li>An app including a Table View Controller and a View Controller providing a Text Field and a Slider (See screenshots above)<\/li>\n<\/ul>\n<p>This article focuses on using the LoopBack iOS SDK in Swift and thus we won&#8217;t cover creating View Controllers and its Actions. You might want to check out this tutorial provided by Apple to get a started:<br \/>\n<a href=\"https:\/\/developer.apple.com\/library\/ios\/referencelibrary\/GettingStarted\/DevelopiOSAppsSwift\/Lesson9.html#\/\/apple_ref\/doc\/uid\/TP40015214-CH9-SW1\" target=\"_blank\">Start Developing iOS Apps (Swift): Implement Edit and Delete Behavior<\/a><\/p>\n<h2>Getting Started<\/h2>\n<p>Start the <a href=\"https:\/\/github.com\/kgoedecke\/loopback-swift-crud-example\/tree\/master\/loopback-swift-crud-example-tests\/server\" target=\"_blank\">LoopBack Test App<\/a> by running <span class=\"lang:default decode:true crayon-inline \">node .<\/span>\u00a0 in the main folder. The Test App will by default listen on <span class=\"lang:default decode:true crayon-inline\">http:\/\/localhost:3000<\/span> .<\/p>\n<p>In order to access the LoopBack Backend from your Swift App we will add an instance of <em>LBRESTAdapter<\/em> to the applications <em>AppDelegate<\/em>.<\/p>\n<p>Open <em>AppDelegate.swift<\/em> and insert the following right after <span class=\"lang:default decode:true crayon-inline\">var window: UIWindow?<\/span><\/p>\n<pre class=\"lang:default decode:true\">static let adapter = LBRESTAdapter(URL: NSURL(string: \"http:\/\/localhost:3000\"))<\/pre>\n<p>This way we can access the adapter from everywhere in the project.<\/p>\n<h2>Subclassing LBPersistedModelRepository &amp; LBPersistedModel<\/h2>\n<p>The LoopBack Test App provides a Model named &#8220;<em>Widgets<\/em>&#8220;, which has multiple attributes, as you can see in this JavaScript snippet from the source code of the LoopBack Test app.<\/p>\n<pre class=\"lang:default decode:true\">var Widget = app.model('widget', {\r\n  properties: {\r\n    name: {\r\n      type: String,\r\n      required: true\r\n    },\r\n    bars: {\r\n      type: Number,\r\n      required: false\r\n    }, ...<\/pre>\n<p>We are only going to use the <em>name <\/em>(type: String) and the <em>bars<\/em> (type: Number) attribute.<\/p>\n<p>All data corresponding to a Model is handled by a Repository in the LoopBack iOS SDK. The Repository can then be used to create new models, update existing ones or simply retrieve all currently stored ones. As every model has individual attributes we need to create a Subclass of <em>LBPersistedModelRepository<\/em> and <em>LBPersistedModel<\/em> and declare those attributes as well as the custom model name.<\/p>\n<p>Create a new Swift file, name it &#8220;<em>WidgetRepository.swift<\/em>&#8221; and insert the following code:<\/p>\n<pre class=\"nums:true lang:default decode:true\">import Foundation\r\n\r\nclass WidgetRepository : LBPersistedModelRepository     {\r\n    override init() {\r\n        super.init(className: \"widgets\")\r\n    }\r\n    class func repository() -&gt; WidgetRepository {\r\n        return WidgetRepository()\r\n    }\r\n}<\/pre>\n<p><strong>Line 3:<\/strong> Creates a subclass of <em>LBPersistedModelRepository <\/em>named<em> WidgetRepository<\/em>, which will later be used to perform the CRUD operations.<\/p>\n<p><strong>Line 4:<\/strong> Specify the initializer methods and simply call <em>initWithClassName\u00a0<\/em>from the <em>LBPersistedModelRepository <\/em>class<em><br \/>\n<\/em><\/p>\n<p><strong>Line 7:<\/strong> Provides a class function that returns an object of the WidgetRepository class<\/p>\n<p>Afterwards create an other Swift file named &#8220;<em>Widget.swift<\/em>&#8221; with the following code:<\/p>\n<pre class=\"lang:default decode:true \">class Widget : LBPersistedModel {\r\n    var name: String!\r\n    var bars: NSNumber!\r\n    var date: NSDate!\r\n    var data: NSObject!\r\n}<\/pre>\n<p>This creates a Subclass of the <em>LBPersistedModel<\/em> and introduces the attributes that each Widget object contains.<\/p>\n<h2>WidgetRepository<\/h2>\n<p>To perform basic CRUD operations as simple as possible from everywhere in your app add an other static var of type WidgetRepository to your AppDelegate.<em>\u00a0<\/em>The WidgetRepository object will\u00a0provide functionality to create new models, updates existing models\u00a0or simply\u00a0retrieve data.<\/p>\n<p>Right after your LBRESTAdapter in AppDelegate.swift create the instance of WidgetRepository:<\/p>\n<p>Insert the following code:<\/p>\n<pre class=\"nums:true wrap:false lang:default decode:true\">static let widgetRepository = adapter.repositoryWithClass(WidgetRepository) as! WidgetRepository<\/pre>\n<h2>Displaying all Widgets<\/h2>\n<p>By now you should already have a <em>TableViewController<\/em> in your project that will display all Widget Models in a TableView. Open this Table View Controller now.<\/p>\n<p>Insert the following in your Class:<\/p>\n<pre class=\"lang:default decode:true\">var widgets = [Widget]()<\/pre>\n<p>This\u00a0Array of <em>Widgets\u00a0<\/em>will hold the elements that will be displayed in the Table View.<\/p>\n<p>In\u00a0<span class=\"lang:default decode:true crayon-inline \">viewDidLoad()<\/span>\u00a0 we are going to call\u00a0<span class=\"lang:default decode:true crayon-inline\">allWithSuccess()<\/span>\u00a0on our widgetRepository to retrieve all Models and in the Callback assign the local widgets Array (<span class=\"lang:default decode:true crayon-inline \">self.widgets<\/span>\u00a0) to the fetched Widgets from the remote Backend:<\/p>\n<pre class=\"lang:default decode:true\">AppDelegate.widgetRepository.allWithSuccess({ (fetchedWidgets: [AnyObject]!) -&gt; Void in\r\n\t\tself.widgets = fetchedWidgets as! [Widget]\r\n\t\tself.tableView.reloadData()\r\n\t}, failure: { (error: NSError!) -&gt; Void in\r\n\t    NSLog(error.description)\r\n})<\/pre>\n<p>Next in <span class=\"lang:default decode:true crayon-inline\">tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)<\/span> dequeue a Reusable Cell and set its values to the ones of the appropriate Widget element (we assume that you created a custom <em>UITableViewCell<\/em> with two Outlets for the &#8220;name&#8221; and the &#8220;bars&#8221; numerical value):<\/p>\n<pre class=\"lang:default decode:true\">let cell = tableView.dequeueReusableCellWithIdentifier(\"tableCell\", forIndexPath: indexPath) as! WidgetTableViewCell\r\ncell.nameLabel.text = widgets[indexPath.row].name\r\ncell.valueLabel.text = String(widgets[indexPath.row].bars)\r\nreturn cell<\/pre>\n<p>Checkpoint: If you run your app now, then you should be able to see all the Widgets in your <em>TableViewController<\/em>.<\/p>\n<h2>Deleting a Widget<\/h2>\n<p>Your Table View Controller should also contain the <span class=\"lang:default decode:true crayon-inline \">tableView(_:commitEditingStyle:forRowAtIndexPath:)<\/span> delegate function if you enabled the editing mode. Add the following snippet:<\/p>\n<pre class=\"lang:default decode:true\">override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {\r\n    if editingStyle == .Delete {\r\n        \/\/ Delete the row from the data source\r\n        widgets[indexPath.row].destroyWithSuccess({ () -&gt; Void in\r\n            self.widgets.removeAtIndex(indexPath.row)\r\n            self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)\r\n            }, failure: { (error: NSError!) -&gt; Void in\r\n                NSLog(error.description)\r\n        })\r\n    }\r\n}<\/pre>\n<p>Here we trigger the deletion of a Widget. If the user deletes a Widget, we first remove it from the Backend by calling <em>destroyWithSuccess<\/em> on the repository and then from the local Array as well as from the Table View.<\/p>\n<h2>Creating and Updating Widgets<\/h2>\n<p>Open the View Controller for the detail view of the Widget.<\/p>\n<p>In the Class declare a widget variable holding the current Widget object:<\/p>\n<pre class=\"lang:default decode:true\">var widget: Widget?<\/pre>\n<p>In case the View Controller is loaded to update an existing widget we need to fill\u00a0the textfields with the appropriate data.<\/p>\n<p>In <em>viewDidLoad()<\/em> we first check if the local widget object is set and if it is we load the data into the textfield and the slider.<\/p>\n<p>Your <em>viewDidLoad()<\/em> should contain the following now:<\/p>\n<pre class=\"lang:default decode:true\">super.viewDidLoad()\r\nif let widget = widget  {\r\n\tnameTextField.text = widget.name\r\n\tnumberValueSlider.value = widget.bars as Float\r\n}<\/pre>\n<p>At this point we assume that you already created two Segues from the TableViewController in your Storyboard &#8211; One for creating a new Widget and one for updating an existing one.<\/p>\n<p>So your Storyboard should look at this point similar to this:<\/p>\n<p><a href=\"http:\/\/kevingoedecke.com\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard.png\" rel=\"attachment wp-att-237\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-237\" src=\"http:\/\/kevingoedecke.com\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-1024x601.png\" alt=\"loopback-swift-storyboard\" width=\"1024\" height=\"601\" srcset=\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-1024x601.png 1024w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-300x176.png 300w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-768x451.png 768w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard.png 2032w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>Switch back to your Table View Controller and insert the <em>prepareForSegue<\/em> function. Add the following code:<\/p>\n<pre class=\"nums:true wrap:false lang:default decode:true\">override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {\r\n    if segue.identifier == \"ShowDetail\" {\r\n        let widgetDetailViewController = segue.destinationViewController as! WidgetViewController\r\n        if let selectedWidgetCell = sender as? WidgetTableViewCell {\r\n            let indexPath = tableView.indexPathForCell(selectedWidgetCell)!\r\n            let selectedWidget = widgets[indexPath.row]\r\n            widgetDetailViewController.widget = selectedWidget\r\n        }\r\n    }\r\n    else if segue.identifier == \"AddItem\" {\r\n        NSLog(\"Adding new widget\")\r\n    }\r\n    \r\n}<\/pre>\n<p>All that&#8217;s pretty much happening here is that if the <em>segue.identifier<\/em> is equal to <em>&#8220;ShowDetail&#8221;<\/em> we set the destinationViewControllers widget object to the currently selected Widget of the Table View Controller.<\/p>\n<p>Next we will add an <em>IBAction<\/em> to the Table View Controller, which will be triggered when the user hits the Save button in the detail view.<\/p>\n<pre class=\"nums:true wrap:false lang:default decode:true\">@IBAction func unwindToWidgetList(sender: UIStoryboardSegue) {\r\n    if let sourceViewController = sender.sourceViewController as? WidgetViewController, widget = sourceViewController.widget {\r\n        if let selectedIndexPath = tableView.indexPathForSelectedRow {\r\n            widgets[selectedIndexPath.row] = widget\r\n            tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None)\r\n        }\r\n        else    {\r\n            let newIndexPath = NSIndexPath(forRow: widgets.count, inSection: 0)\r\n            self.widgets.append(widget)\r\n            self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom)\r\n        }\r\n    }\r\n}<\/pre>\n<p><strong>Line 3:<\/strong> By checking if a row in the table view was selected we determine\u00a0if the user updated an existing Widget or if he created a new one.<\/p>\n<p><strong>Line 4-5:<\/strong> In case the user updated an existing Widget we simply reload the row, as the update is being handled in the detail view controller.<\/p>\n<p><strong>Line 8-10:<\/strong> In case the user added a new Widget, we take the <em>sourceViewControllers<\/em> widget object and append it to the local array of Widgets. Afterwards we insert a new row into the <em>TableView<\/em>. The actual creation of the widget is being handled within the Detail View Controller.<\/p>\n<p>Next open the Storyboard and add an Action Segue from the Save button to trigger the <em>unwindToWidgetList<\/em> as shown in the screenshot below:<\/p>\n<p><a href=\"http:\/\/kevingoedecke.com\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-2.png\" rel=\"attachment wp-att-241\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-241\" src=\"http:\/\/kevingoedecke.com\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-2-1024x586.png\" alt=\"loopback-swift-storyboard-2\" width=\"1024\" height=\"586\" srcset=\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-2-1024x586.png 1024w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-2-300x172.png 300w, https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-storyboard-2-768x439.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>Now open your Detail View Controller and override the <em>prepareForSegue<\/em> function:<\/p>\n<pre class=\"nums:true wrap:false lang:default decode:true\">override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {\r\n    if saveButton === sender {\r\n        if let _ = widget {\r\n            widget!.name = nameTextField.text ?? \"\"\r\n            widget!.bars = Int(numberValueSlider.value)\r\n            widget?.saveWithSuccess({ () -&gt; Void in\r\n                NSLog(\"Successfully updated Widget\")\r\n                }, failure: { (error: NSError!) -&gt; Void in\r\n                    NSLog(error.description)\r\n            })\r\n        }\r\n        else    {\r\n            if let name = nameTextField.text where name != \"\" {\r\n                widget = AppDelegate.widgetRepository.modelWithDictionary(nil) as? Widget\r\n                widget!.name = name\r\n                widget!.bars = Int(self.numberValueSlider.value)\r\n                widget?.saveWithSuccess({ () -&gt; Void in\r\n                    NSLog(\"Successfully created new Widget\")\r\n                    }, failure: { (error: NSError!) -&gt; Void in\r\n                        NSLog(error.description)\r\n                })\r\n            }\r\n        }\r\n    }\r\n}<\/pre>\n<p>If the <em>SaveButton<\/em> was clicked we determine if the user is creating a new Widget or updating an exiting one.<\/p>\n<p><strong>Line 4-5: <\/strong>Sets the attributes of the local widget object to the updated values<\/p>\n<p><strong>Line 6-10:<\/strong>\u00a0Then we call saveWithSuccess to save the changes to the LoopBack backend<\/p>\n<p><strong>Line 14-16:<\/strong> If the user is creating a new Widget then we instantiate a new Widget with <em>modelWithDictionary(nil)<\/em> and set its values accordingly<\/p>\n<p><strong>Line 17:<\/strong>\u00a0Save the newly created Widget. By finally executing saveWithSuccess the object gets assigned its internal id value and gets created\u00a0on the LoopBack Backend.<\/p>\n<h2>Done<\/h2>\n<p>That&#8217;s it now! By now you should have a Swift app using the LoopBack iOS SDK that provides CRUD functionality for the Widget model.<\/p>\n<p>If you have any questions or feedback, just post a comment \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Key Features Swift Example App accessing a LoopBack Backend providing basic Create, Read, Update and Delete operations Supports iOS 9, written in Swift 2 Uses the official Loopback iOS SDK Source code includes LoopBack Server Test App Source Code Available on GitHub: https:\/\/github.com\/kgoedecke\/loopback-swift-crud-example Screenshots Prerequisites Deployed LoopBack Test App available here: GitHub: kgoedecke\/loopback-swift-crud-example &#8211; LoopBack [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":212,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[15],"tags":[20,16,24,21,23,17,19],"class_list":["post-211","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming","tag-cocoapods","tag-loopback","tag-loopback-ios","tag-loopback-sdk","tag-loopback-swift-example","tag-strongloop","tag-swift"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.8.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>LoopBack Swift Example CRUD App - Kevin Goedecke<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"LoopBack Swift Example CRUD App - Kevin Goedecke\" \/>\n<meta property=\"og:description\" content=\"Key Features Swift Example App accessing a LoopBack Backend providing basic Create, Read, Update and Delete operations Supports iOS 9, written in Swift 2 Uses the official Loopback iOS SDK Source code includes LoopBack Server Test App Source Code Available on GitHub: https:\/\/github.com\/kgoedecke\/loopback-swift-crud-example Screenshots Prerequisites Deployed LoopBack Test App available here: GitHub: kgoedecke\/loopback-swift-crud-example &#8211; LoopBack [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/\" \/>\n<meta property=\"og:site_name\" content=\"Kevin Goedecke\" \/>\n<meta property=\"article:published_time\" content=\"2015-12-29T23:33:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2016-01-07T14:48:10+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"900\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Kevin Goedecke\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kevin Goedecke\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/\",\"url\":\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/\",\"name\":\"LoopBack Swift Example CRUD App - Kevin Goedecke\",\"isPartOf\":{\"@id\":\"https:\/\/kevingoedecke.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg\",\"datePublished\":\"2015-12-29T23:33:53+00:00\",\"dateModified\":\"2016-01-07T14:48:10+00:00\",\"author\":{\"@id\":\"https:\/\/kevingoedecke.com\/#\/schema\/person\/4b156cd6453e1af4bab9076b0a663871\"},\"breadcrumb\":{\"@id\":\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#primaryimage\",\"url\":\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg\",\"contentUrl\":\"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg\",\"width\":1800,\"height\":900},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kevingoedecke.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"LoopBack Swift Example CRUD App\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kevingoedecke.com\/#website\",\"url\":\"https:\/\/kevingoedecke.com\/\",\"name\":\"Kevin Goedecke\",\"description\":\"Founder. Entrepreneur.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kevingoedecke.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/kevingoedecke.com\/#\/schema\/person\/4b156cd6453e1af4bab9076b0a663871\",\"name\":\"Kevin Goedecke\",\"url\":\"https:\/\/kevingoedecke.com\/blog\/author\/kgoedecke\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"LoopBack Swift Example CRUD App - Kevin Goedecke","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/","og_locale":"en_US","og_type":"article","og_title":"LoopBack Swift Example CRUD App - Kevin Goedecke","og_description":"Key Features Swift Example App accessing a LoopBack Backend providing basic Create, Read, Update and Delete operations Supports iOS 9, written in Swift 2 Uses the official Loopback iOS SDK Source code includes LoopBack Server Test App Source Code Available on GitHub: https:\/\/github.com\/kgoedecke\/loopback-swift-crud-example Screenshots Prerequisites Deployed LoopBack Test App available here: GitHub: kgoedecke\/loopback-swift-crud-example &#8211; LoopBack [&hellip;]","og_url":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/","og_site_name":"Kevin Goedecke","article_published_time":"2015-12-29T23:33:53+00:00","article_modified_time":"2016-01-07T14:48:10+00:00","og_image":[{"width":1800,"height":900,"url":"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg","type":"image\/jpeg"}],"author":"Kevin Goedecke","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Kevin Goedecke","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/","url":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/","name":"LoopBack Swift Example CRUD App - Kevin Goedecke","isPartOf":{"@id":"https:\/\/kevingoedecke.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#primaryimage"},"image":{"@id":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#primaryimage"},"thumbnailUrl":"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg","datePublished":"2015-12-29T23:33:53+00:00","dateModified":"2016-01-07T14:48:10+00:00","author":{"@id":"https:\/\/kevingoedecke.com\/#\/schema\/person\/4b156cd6453e1af4bab9076b0a663871"},"breadcrumb":{"@id":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#primaryimage","url":"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg","contentUrl":"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg","width":1800,"height":900},{"@type":"BreadcrumbList","@id":"https:\/\/kevingoedecke.com\/blog\/2015\/12\/29\/loopback-swift-example-crud-app\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kevingoedecke.com\/"},{"@type":"ListItem","position":2,"name":"LoopBack Swift Example CRUD App"}]},{"@type":"WebSite","@id":"https:\/\/kevingoedecke.com\/#website","url":"https:\/\/kevingoedecke.com\/","name":"Kevin Goedecke","description":"Founder. Entrepreneur.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kevingoedecke.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/kevingoedecke.com\/#\/schema\/person\/4b156cd6453e1af4bab9076b0a663871","name":"Kevin Goedecke","url":"https:\/\/kevingoedecke.com\/blog\/author\/kgoedecke\/"}]}},"jetpack_featured_media_url":"https:\/\/kevingoedecke.com\/blog\/wp-content\/uploads\/2015\/12\/loopback-swift-example-crud@2x.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/posts\/211","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/comments?post=211"}],"version-history":[{"count":33,"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/posts\/211\/revisions"}],"predecessor-version":[{"id":250,"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/posts\/211\/revisions\/250"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/media\/212"}],"wp:attachment":[{"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/media?parent=211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/categories?post=211"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kevingoedecke.com\/blog\/wp-json\/wp\/v2\/tags?post=211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}