Using Core Data in iOS with RubyMotion
Learn how to use Core Data in a simple RubyMotion app. By Gavin Morrice.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Using Core Data in iOS with RubyMotion
30 mins
- Getting Started
- Adding the Tasks Button
- Adding the Tasks List Screen
- Populating the Tasks List with Real Data
- Installing CDQ
- Creating a Data Model
- Be the Boss of cdq
- CDQ Helper Methods
- Loading Tasks from the Database
- Creating New Tasks
- Selecting the Current Task
- Editing the Tasks List
- Where To Go From Here?
If you’re looking to add persistence to your iOS or OS X app, Core Data is great choice — and implementing it in RubyMotion is surprisingly simple.
In this tutorial, you’ll use Core Data to add persistence to the Pomotion timer I showed you in how to make in my RubyMotion Tutorial for Beginners series.
If you have a good understanding of RubyMotion, feel free to download the complete code from the GitHub repository and start from there.
Otherwise, I’d suggest working through those two tutorials before starting this one.
You’ll need the following to get the most out of this RubyMotion tutorial:
- Experience developing for iOS in Objective-C
- Basic understanding of Ruby
- Basic knowledge of CSS
- Basic experience using Terminal
Prior experience with Core Data or ActiveRecord would also be a huge plus, but neither is essential.
Getting Started
First, make sure you have the final project from the previous tutorial series or grab it from GitHub.
Open Terminal, switch to the root directory of the application, and make sure the app builds successfully by running the following command:
rake device_name="iPhone 4s"
device_name
for the rake command that lets you specify which device simulator the app will run on. I prefer to use the iPhone 4s simulator because it’s smaller and I can see everything on the screen.
If your screen looks like this, great — If it doesn’t, make sure you’ve followed the installation instructions and completed all of the steps in the previous Pomotion tutorials.
Once you have Pomotion running, you’re ready to begin.
gem update bundler
.
Additionally, you may see an error something like Bundler::GemNotFound: Couldn’t find sass-3.4.2 in any of the sources. If you encounter this issue, you can explicitly install Sass v3.4.2 with the following: gem install sass -v 3.4.2
Adding the Tasks Button
You’re going to add a tasks list to the Pomotion app. Think of this as a user’s daily TODO list where users add and remove tasks, as well as select a task to work on.
Users access the tasks list by tapping a button in the navigation bar. So, you’ll start by adding that button.
Using your favorite text editor, open app/controllers/main_view_controller.rb and add the following lines under the timer_button
method definition.
def tasks_button
@tasks_button ||= UIBarButtonItem.alloc.initWithImage(tasks_image,
style: UIBarButtonItemStylePlain, target: self, action: nil)
end
def tasks_image
@tasks_image ||= UIImage.imageNamed('todo.png')
end
Here you’ve defined two properties on the MainViewController class: a UIBarButtonItem named tasks_button
, and a UIImage named tasks_image
.
Before you run these changes, you’ll need to add the image file referenced in the tasks_image method above to your app’s resources.
Download this file and save it to your application’s resources directory as todo.png.
Still in app/controllers/main_view_controller.rb, add this method below the tasks_image
method:
def viewDidLoad
super
self.title = "Pomotion"
self.navigationItem.rightBarButtonItem = tasks_button
end
This adds the tasks_button
to MainViewController’s navigation bar. Build and run your app the same way you did the last time to see the changes:
rake device_name="iPhone 4s"
Looking good so far! However, the color scheme for this app is red, white and green. That blue tint on the tasks_button
is a bit clashy, don’t you think? Good thing you can change that!
You might remember from the previous Pomotion tutorial that Pomotion uses PixateFreestyle to add CSS styles to your app’s views. This means that you’ll find style definition in a CSS file named resources/default.css.
Open resources/default.css and add the following line to the navigation-bar selector:
-ios-tint-color: white;
This changes the tint color of the navigation bar to white. To learn more, check out the Pixate reference.
Save the file then build and run the app again with rake device_name="iPhone 4s"
. The tasks button should now have a white tint instead of blue.
Wasn’t that easy? :]
Try tapping the tasks_button. Nada. Why isn’t it responding? Oh, because you haven’t defined an action to be called when it’s tapped.
Adding the Tasks List Screen
In Terminal, create a new file in the app/controllers directory named tasks_view_controller.rb:
touch app/controllers/tasks_view_controller.rb
Open the file in your text editor.
Declare TasksViewController as a subclass of UITableViewController like the following:
class TasksViewController < UITableViewController
end
Save the file, and open main_view_controller.rb and add the following just after timer_button_tapped:
.
def tasks_button_tapped(sender)
tasks_controller = TasksViewController.alloc.initWithNibName(nil, bundle: nil)
navigationController.pushViewController(tasks_controller, animated: true)
end
This displays the tasks list when the user taps the tasks_button
.
Now wire up this method to the action:
parameter in tasks_button
with this:
def tasks_button
@tasks_button ||= UIBarButtonItem.alloc.initWithImage(tasks_image,
style: UIBarButtonItemStylePlain, target: self, action: 'tasks_button_tapped:')
end
Build and run again to launch the app in the simulator
rake device_name="iPhone 4s"
This time, when you tap the tasks_button
you should see an empty table view that looks like this:
Now you're making progress! The UI is mostly configured and now it's time to drill down into the inner workings and make it actually do something more than look pretty.
Populating the Tasks List with Real Data
Installing CDQ
Here comes the fun part...
To use Core Data in your app, you'll be using the Core Data Query gem (or cdq, for short). cdq makes it really easy to get started with Core Data in RubyMotion with just a few lines of code.
I showed you how to install gems to your project in RubyMotion Tutorial for Beginners: Part 1, but you can read the Pixate Freestyle section if you need a refresher.
Open your Gemfile and add the following line:
gem 'cdq'
Then make sure it's installed by running this command in Terminal:
$ bundle install
Now that cdq is installed, run the following command in Terminal to complete the installation:
cdq init
The cdq init
command does a couple of things, and it's quite important that you understand them both.
First, it creates an initial schema file named 0001_initial.rb in a new directory named schemas. These schema files are where you define and manage your application's database structure.
Each time you need to make a change to one of the tables, you create a new schema file that reflects how the new database should look. As long as the versions are not too different from each other, Core Data automatically migrates your database and updates the structure without you having to do anything else.
The second thing cdq init
does is that it adds another line to the bottom of your Rakefile, like this:
task :"build:simulator" => :"schema:build"
In short, this makes sure that each time you build the app to run in the simulator, the rake schema:build
command also runs to keep the schema up to date.
This is extremely helpful, but there's a potential pitfall: If you're deploying to an iOS device instead of the simulator, this command doesn't run automatically — you'll have to run it manually from Terminal by running:
rake "schema:build"
Now, open app/app_delegate.rb and include CDQ
by adding the following line just below AppDelegate
:
include CDQ
And finally, add the following line to the start of application:didFinishLaunchingWithOptions
cdq.setup
And that's it for the installation. Next up is setting up your first data model.
Creating a Data Model
Open schemas/0001_initial.rb in your text editor, and you'll see some example code that's been commented out. Delete that and add the following in its place:
schema "0001 initial" do
entity "Task" do
string :name, optional: false
end
end
This code defines a simple entity named Task. A Task has a name (defined as a string), which is required for a Task record to be valid (it's not optional).
There's one more step to finish adding your Task model, and that's to create a class for it in your application. In your text editor, create a file named task.rb in the app/models directory and define Task
like so:
class Task < CDQManagedObject
end
The CDQManagedObject
superclass is provided by CDQ, and it provides some extra methods for querying and saving data to your database.
Build and run the app in the simulator so you can try out CDQ in the console:
rake device_name="iPhone 4s"
Still in Terminal, run the following command once the app launches:
(main)> Task.count
It should return the number of Tasks currently in the database (which is currently 0):
(main)> Task.count => 0
Create a new Task by typing the following:
Task.create(name: "My first task")
The output should look similar to this:
(main)> Task.create(name: "My first task") => <Task: 0x11750b10> (entity: Task; id: 0x1174d940 <x-coredata:///Task/t2FA02CA9-05AF-4BD5-BAEB-B46F21637D0C2> ; data: { name = "My first task"; })
Now when you call Task.count
, you should see it return 1.
(main)> Task.count => 1
Quit the simulator (by pressing ctrl + c), and then build and run the app once again.
rake device_name="iPhone 4s"
Fetch the number of Tasks once again by running Task.count
, it should return 1.
(main)> Task.count => 0
...it should, but it didn't! What happened?!
Be the Boss of cdq
CDQ won't commit any data to the database unless you tell it to, and you do that by calling cdq.save
in your code. This is an important gotcha to keep in mind.
Your application will not persist data unless you call this method. This is a deliberate feature of cdq; by only making commits to the database when you've defined all of the changes to be committed, you'll improve the memory usage and performance of your app.
It's easy to forget about this extra step – especially if you're coming to iOS from Ruby on Rails.
So start again from the top by create a new Task:
(main)> Task.create(name: "This is my first task") => <Task: 0xb49aec0> (entity: Task; id: 0xb49aef0 <x-coredata:///Task/t41D7C6A6-806D-4490-90A6-19F1E61ED6C12> ; data: { name = "This is my first task"; })
But this time, run the following command afterwards:
(main)> Task.save => true
Now quit your application and then re-launch. Call Task.count
, and you'll see it returns 1.
(main)> Task.count => 1
CDQ Helper Methods
CDQ offers a few other helpful methods to save and retrieve persisted data. Run the following commands in the console to see their results.
Fetch the first row:
(main)> Task.first => <Task: 0xb49aec0> (entity: Task; id: 0xb47a830 <x-coredata://B0AEB5CD-2B77-43BA-B78B-93BA98325BA0/Task/p1> ; data: { name = "This is my first task"; })
Check if there are any records:
(main)> Task.any? => true
Find rows that match given constraints:
(main)> Task.where(name: "This is my first task").any? => true (main)> Task.where(name: "This is my second task").any? => false
Delete a row:
(main)> Task.first.destroy => #<NSManagedObjectContext:0xad53ed0>
And most importantly, commit changes to the database:
(main)> Task.save => true
You'll use these methods again soon -- when you complete the tasks list feature.
Loading Tasks from the Database
The Tasks screen should show each of today's Tasks that are in the database. First, though, you should prepare for the initial condition when there are no tasks.
Add the following implementation In tasks_view_controller.rb:
class TasksViewController < UITableViewController
# 1
# = UITableViewDelegate =
def tableView(table_view, heightForRowAtIndexPath: index_path)
todays_tasks.any? ? 75.0 : tableView.frame.size.height
end
# 2
# = UITableViewDataSource =
def tableView(table_view, cellForRowAtIndexPath: index_path)
table_view.dequeueReusableCellWithIdentifier(EmptyCell.name)
end
# 3
def tableView(table_view, numberOfRowsInSection: section)
[1, todays_tasks.count].max
end
# 4
private
def todays_tasks
Task.all
end
end
Most of this code should seem pretty familiar to you by now, except for the last method, but I'll walk you through each of them.
- First, you define
tableView:heightForRowAtIndexPath
from the UITableViewDelegate delegate. If there are any tasks in the database, then the height of each cell should be 75 points, otherwise, a cell's height should be the entire height of the UITableView. - Next, in
tableView:cellForRowAtIndexPath:
you return an instance of EmptyCell -- you'll define this class in a moment. - The
tableView:numberOfRowsInSection:
method should return 1 if there are no tasks in the database, or the number of tasks if there are any. This ensures that if the list of tasks is empty, the app still displays one cell. - Finally,
todays_tasks
is a helper method that loads all of the tasks from the database.Although you could easily just call
Task.all
throughout the various methods inTasksViewController
, it's good practice to define a method like this to access each of the objects or collections you load from the database.Having this single point of access is much DRY-er (Don't Repeat Yourself), and it means you only have to change the code once if you need to add extra constraints later.
Now add this:
def viewDidLoad
super
tableView.registerClass(EmptyCell, forCellReuseIdentifier: EmptyCell.name)
end
You've just registered the EmptyCell
view class with TasksViewController's tableView
by defining viewDidLoad
.
Before you build the app again, you'll also need to create the actual class for the empty table view cell, so create a new file in the app/views directory named empty_cell.rb, like this:
touch app/views/empty_cell.rb
Now add this…
class EmptyCell < UITableViewCell
end
to define the EmptyCell class as a subclass of UITableViewCell.
Build and run the app in your simulator once again with this command:
rake device_name="iPhone 4s"
Now when you tap the tasks button, you'll see a screen like this
If you see multiple cells or an error message, make sure that you've deleted all of the Tasks from the database by calling Task.destroy_all
followed by Task.save
in the app console.
Wouldn't this be more user friendly if it had a title? Of course it would. In tasks_view_controller.rb, update the viewDidLoad
method like so:
def viewDidLoad
super
self.title = "Tasks"
tableView.registerClass(EmptyCell, forCellReuseIdentifier: EmptyCell.name)
end
This time, when you build and run the app you should see the title Tasks in the navigation bar on the tasks screen.
Now you need to give the users a means of adding new tasks to the list. First, create an "Add" button with the following method:
def add_button
@add_button ||= UIBarButtonItem.alloc.
initWithBarButtonSystemItem(UIBarButtonSystemItemAdd, target: self, action: nil)
end
Then, add the following line at the bottom of viewDidLoad
:
navigationItem.rightBarButtonItem = add_button
This, of course, adds the button to the right of your navigation bar. Build and run the app again, and you'll see a new + button that makes it possible to add new tasks.
Most users will understand that the plus button is how you add tasks, but just to be on the safe side leave a hint that helps the user see how to add tasks.
To do this, simply add a message to the empty cell that tells the user how to add a task. Add the following method to empty_cell.rb:
def initWithStyle(style, reuseIdentifier: reuseIdentifier)
super.tap do
self.styleClass = 'empty_cell'
textLabel.text = "Click '+' to add your first task"
end
end
Of course, the label needs a little styling before it's complete, otherwise, it'll be ugly. So, add the following CSS rules to resources/default.css
.empty_cell label {
top: 200px;
left: 0;
width: 320px;
height: 30px;
font-size: 18px;
color: #AAAAAA;
text-align: center;
}
Build and run the app again with rake device_name="iPhone 4s"
. The tasks screen should now look like this:
Looking good!
Creating New Tasks
Okay, so far you've got the framework mostly there, but the only way to add tasks is a tad complex for the average user.
So, in tasks_view_controller.rb add a UIAlertView
property under add_button
to prompt the user to enter the new task's name:
def task_alert_view
@task_alert_view ||= UIAlertView.alloc.initWithTitle("Add A Task",
message: "Insert the name of the task below",
delegate: self, cancelButtonTitle: "Add", otherButtonTitles: nil).tap do |alert|
alert.alertViewStyle = UIAlertViewStylePlainTextInput
end
end
By setting the alertViewStyle property to UIAlertViewStylePlainTextInput, you make it so the alert view contains a text field that the user can populate and submit.
All you need to do now is define an action to show this alert view, so add the following method:
def add_button_tapped(sender)
task_alert_view.show
end
Then, update the action:
parameter in add_button
to call add_button_tapped:
:
def add_button
@add_button ||= UIBarButtonItem.alloc.
initWithBarButtonSystemItem(UIBarButtonSystemItemAdd, target: self, action: 'add_button_tapped:')
end
Before this will work as expected, you'll have to implement the UIAlertViewDelegate method alertView:clickedButtonAtIndex in TasksViewController.
Add the following at the bottom of the implementation:
# = UIAlertViewDelegate =
def alertView(alert_view, clickedButtonAtIndex: index_path)
text_field = alert_view.textFieldAtIndex(0)
if !text_field.text.to_s.empty?
create_new_task(name: text_field.text)
tableView.reloadData
text_field.text = ''
end
end
private
def create_new_task(attributes)
Task.create(attributes)
Task.save
end
This method first assigns the text field from the alert view to an instance variable and checks if it's text property has a value.
If it does, the controller creates a new Task record by calling create_new_task
, a private method that creates a new record and commits the changes to the database.
Then, you reload the tableView to show the newly added task in the list, and reset the text_field's text property back to an empty string.
Build and run the app once again, and add a new task to the tasks list:
But what happens when you add a task? Where does it go?
The tasks in your database won't display on screen yet, because the tableView cells haven't been configured to display them. To do that, create a new file in app/views named task_cell.rb.
touch app/views/task_cell.rb
Just like EmptyCell
, TaskCell
should be a subclass of UITableViewCell
. Open task_cell.rb and add the following:
class TaskCell < UITableViewCell
end
And also add the following lines to TaskCell
def initWithStyle(style, reuseIdentifier: reuseIdentifier)
super.tap do
self.styleClass = 'task_cell'
end
end
def configure_for_task(task)
textLabel.text = task.name
end
def prepareForReuse
super
textLabel.text = ''
end
Here you redefine initWithStyle:reuseIdentifier
and set a styleClass for the cell, just like you did in EmptyCell
. configure_for_task
lets you set the value of the cell's textLabel from TasksViewController
.
prepareForReuse
should be familiar to you. In this case, you're setting the text
property of the textLabel
inherited from UITableViewCell
back to an empty string, so the cell may be reused again by the table view. In this case, it's not strictly necessary, although it's always good practice.
Go back to tasks_view_controller.rb and tell your tableView about TaskCell
the same way you did with the EmptyCell
class, by updating viewDidLoad
to the following:
def viewDidLoad
super
tableView.registerClass(EmptyCell, forCellReuseIdentifier: EmptyCell.name)
tableView.registerClass(TaskCell, forCellReuseIdentifier: TaskCell.name)
navigationItem.rightBarButtonItem = add_button
end
Finally, update tableView:cellForRowAtIndexPath:
to return a TaskCell
if there are tasks present.
def tableView(table_view, cellForRowAtIndexPath: index_path)
if todays_tasks.any?
task = todays_tasks[index_path.row]
table_view.dequeueReusableCellWithIdentifier(TaskCell.name).tap do |cell|
cell.configure_for_task(task)
end
else
table_view.dequeueReusableCellWithIdentifier(EmptyCell.name)
end
end
Build and run the app again. Now the task list will update with new tasks as you add them.
Things are really coming together.
Selecting the Current Task
So as of now, the app functions, but there's always more you can do to kick it up a notch. In this case, you could display the name of the current task on the timer screen. That would certainly help the user stay focused on the current task.
To get this working, you'll first need to add a column to the tasks table to identify which task is the current one. Update the table by defining the new schema in the schemas directory.
Create a new file named 0002_add_current_to_tasks.rb
touch schemas/0002_add_current_to_tasks.rb
Edit this file in your text editor so it looks like this:
schema "0002 add current to tasks" do
entity "Task" do
string :name, optional: false
boolean :current, default: false, optional: false
end
end
This file is very similar to the previous schema file you created.
In fact, there are only two differences: The name of the schema 0002 add current to tasks and the additional line where the current column is defined. In this case, it's a boolean column with a default value of false, which must be set for the Task record to be valid.
That's all you need to do!
The next time you run rake device_name="iPhone 4s"
your app should automatically update the tasks table to match the new schema version.
Add a label to the main screen to display the name of the current task. In main_view.rb add this new property:
def task_name_label
@task_name_label ||= UILabel.alloc.initWithFrame(CGRectZero).tap do |label|
label.styleClass = 'task_name_label'
label.text = "n/a"
end
end
Again, nothing too crazy here. task_name_label
returns a UILabel
where text
is pre-populated with n/a (not available, as there may not be a current task set when the screen is loaded). The label is given a style class task_name_label
, so that you can easily define how it looks using CSS.
Update initWithFrame
to add the task_name_label
as a subview:
def initWithFrame(frame)
super.tap do
self.styleId = 'main_view'
addSubview(timer_label)
addSubview(timer_button)
addSubview(task_name_label)
end
end
Then you need to open resources/default.css and add some new CSS:
.task_name_label {
top: 400px;
left: 60px;
width: 200px;
height: 30px;
font-size: 16px;
color: #333333;
text-align: center;
}
Build and run the app once again:
rake device_name="iPhone 4s"
Now you should see a label with n/a showing underneath the main timer:
The text
for this label needs to be populated with the name of the current task whenever this screen displays. That way, it'll update when the current task changes.
In your text editor, open app/models/task.rb and add the following class methods:
# 1
def self.current=(task)
self.current.current = false if self.current
# 2
task.current = true
# 3
self.save
# 4
@current = task
end
# 5
def self.current
@current ||= where(current: true).first
end
# 6
def self.reset_current
@current = nil
end
Let's review this section by section:
-
Task::current=
is a setter method that sets the current Task. First, it checks for any existing current tasks and sets their current property to false. - This sets current on the given task to true.
- This saves the changes -- remember, CDQ won't commit any changes to the database unless you call the
save
method. - Finally,
Task::current=
sets an instance variable to store the new current Task. -
Task::current
returns the value of the@current
instance variable if it's set. If not, it queries the database to find the first Task where the current column is set to true, and then it returns that. - Lastly,
Task::reset_current
sets the value of the@current
back tonil
, ensuring that the new current task reloads the next timeTask::current
is called.
Go back to the tasks_view_controller.rb and implement the UITableViewDelegate
method tableView:didSelectRowAtIndexPath
, just beneath tableView:heightForRowAtIndexPath
:
def tableView(table_view, didSelectRowAtIndexPath: index_path)
Task.current = Task.all[index_path.row]
navigationController.popViewControllerAnimated(true)
end
This block makes it so that when a user taps on a task cell in the tasks screen, it sets the current task, updates that record in the database, and then the app navigates back to the main screen.
There's one small problem here: Currently the user could select the EmptyCell
. You'll prevent it from being selected by implementing the following:
def tableView(table_view, shouldHighlightRowAtIndexPath: index_path)
todays_tasks.any?
end
Give this a try; build and run the app in the simulator.
rake device_name="iPhone 4s"
You won't see any change on the screen yet, and that's because you still need to add that. But if you type the following in Terminal while the simulator is running, you should see that it's working behind the scenes.
(main)> Task.current => <Task: 0xb6a9a60> (entity: Task; id: 0xb63bfa0 <x-coredata://B0AEB5CD-2B77-43BA-B78B-93BA98325BA0/Task/p5> ; data: { current = 1; name = "Write RubyMotion tutorial"; })
Updating the label to show the new task is really simple. In main_view_controller.rb define a wrapper method that returns the task_name_label
for the MainView. Add this just below tasks_image
:
def task_name_label
view.task_name_label
end
Then, insert this private method at the bottom of the MainViewController
implementation:
def set_task_name_label_from_current_task
if Task.current
task_name_label_text = Task.current.name
else
task_name_label_text = "n/a"
end
task_name_label.text = task_name_label_text
end
Finally, implement viewDidAppear:
for MainViewController
and call set_task_name_label_from_current_task
inside there. Remember to call super
inside this method first with this:
def viewDidAppear(animated)
super
set_task_name_label_from_current_task
end
Build and run the app once again to see your changes take effect. This time, when you select a new task, the task_name_label
updates with the name of your chosen task.
Editing the Tasks List
You're almost done; there's just one more thing to add, and this feature is complete!
The user should also be able to remove tasks from the list once they're complete. After all, there's nothing more satisfying than cleaning up your TODO list once your work is complete.
Add this by implementing the UITableViewDelegate methods: tableView:canEditRowAtIndexPath:
and tableView:commitEditingStyle:forRowAtIndexPath:
in tasks_view_controller.rb like so:
# 1
def tableView(table_view, canEditRowAtIndexPath: index_path)
todays_tasks.any?
end
# 2
def tableView(table_view, commitEditingStyle:editing_style, forRowAtIndexPath: index_path)
case editing_style
when UITableViewCellEditingStyleDelete
delete_task_at_index(index_path.row)
if todays_tasks.any?
tableView.deleteRowsAtIndexPaths([index_path],
withRowAnimation: UITableViewRowAnimationFade)
else
tableView.reloadRowsAtIndexPaths([index_path],
withRowAnimation: UITableViewRowAnimationFade)
end
end
end
What's going on here?
-
tableView:canEditRowAtIndexPath:
simply returns true if there are Tasks available to tell the controller that the tasks may be edited. - tableView:commitEditingStyle:forRowAtIndexPath is more involved, and I'll talk you through it:
- First, it checks the value of
editing_style
. Here you're only dealing with the valueUITableViewCellEditingStyleDelete
. If that's the case, the task is deleted by callingdelete_task_at_index
(it's not defined yet). - If there are still other tasks in the database, then this row is deleted from the table view with a nice
UITableViewRowAnimationFade
animation, otherwise, the table reloads to show one EmptyCell with aUITableViewRowAnimationFade
animation.
Now define delete_task_at_index
at the bottom of TasksViewController
, just before the closing end
:
def delete_task_at_index(index)
task = todays_tasks[index]
task.destroy
Task.save
Task.reset_current
end
This private method fetches the task to be destroyed by its index in todays_tasks
, marks it for deletion from the database, and then commits the changes to the database. The last line calls the reset_current
method you defined in Task
to clear the current task.
Build and run your app one more time and try adding and removing some tasks
rake device_name="iPhone 4s"
Where To Go From Here?
That's it. You've successfully implemented Core Data with your RubyMotion app. Hopefully you found it refreshingly straightforward.
Of course, there's a lot more you can achieve with Core Data and RubyMotion than what you've covered here. I recommend you check out the fully documented source code, as well as CDQ's README and documentation.
I'd love to hear about how you've implemented Core Data with RubyMotion, anything you discover while you work through this tutorial and any questions that bubble up as you play around around. Leave your notes, comments and questions below!
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development — plans start at just $19.99/month! Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.
Learn more