3. Tips & Troubleshooting
RubyMotion is still relatively new software and while it works well enough for production usage, in development you’re likely to bump into some quirks and possibly bugs.
Debugging Core Data
Increase the log level
1 $ rake args="-com.apple.CoreData.SQLDebug 3 \
2 -com.apple.CoreData.MigrationDebug 1"
Can be set to 1, 2 or 3 for increasing amounts of debug information.
Core Data Error Codes
A full list of error codes is available in the Core Data Framework API docs.
Code 1570: Missing Mandatory Property
On attempting to save your context, you have a managed object in the context
that is missing a required attribute (i.e. it is set to nil).
Look for NSValidationErrorKey in the error output to find the offending
property. Now you need to trace through your code to find out why this
property is not being set.
1 "Error Domain=NSCocoaErrorDomain Code=1570 \"The operation couldn't be
2 completed. (Cocoa error 1570.)\" UserInfo=0x9826420
3 {NSValidationErrorObject=<Task: 0x8d77f90> (entity: Task; id: 0x8d7ad50
4 <x-coredata:///Task/tAA6226D8-1347-4F26-925B-EE0C3FA3D6802> ; data: {\n
5 completed = nil;\n priority = nil;\n \"task_description\" = nil;\n}),
6 NSValidationErrorKey=completed, NSLocalizedDescription=The operation
7 couldn't be completed. (Cocoa error 1570.)}"
In this case, a Task in the context has no property values set at all. This
particular error refers to the completed property but there will be similar
messages for the priority and task_description properties as well.
This collection of errors will be bundled along with an error of code 1560, which indicates multiple validation problems with the referenced managed object.
Code 134100: Current Schema is Incompatible with Current Store
You have updated your data model (schema) but you already have a persistent store which has been initialised with a schema that is not compatible with the schema you are now trying to load.
Look for the NSStoreModelVersionIdentifiers key in the error message to see
what version the current data store is at.
To correct the situation you either need to:
- Revert your schema (if this was an accidental change),
- Delete the persistent store if you want to start afresh (e.g. run
rake simulator clean=1), - Or migrate the data store. If you are using Core Data Query (CDQ) then follow the steps here, otherwise if you are using pure Core Data you can follow the steps here instead.
Interacting With Views in the Console
One of the key features of RubyMotion is the REPL (Read-Execute-Print-Loop, or console), which makes it easy to interact with your program while it is running. For example, you could add new elements to a view or tweak their attributes until you are happy–certainly much faster than repeatedly changing and hitting ‘Build and Run’ as would be required if we were using Xcode.
One issue you will hit right away though is that there isn’t an easy way to quickly refer to the current view. The following trick is a little ‘dirty’ and you will need to take care to remove such lines from your code after debugging but you can make the current view available via a global variable for easy access in the console.
For example if we have a view controller DetailViewController:
1 class DetailViewController
2 def viewDidLoad
3 $this_view = self
4
5 @textField = UITextField.alloc.initWithFrame([[20, 84], [280, 31]])
6 end
7 end
Now when this view controller has loaded you can access it easily in the console:
1 => $this_view.instance_variable_get('@textField').frame
2 => #<CGRect origin=#<CGPoint x=20.0 y=84.0>
3 size=#<CGSize width=280.0 height=31.0>>
Note how we use instance_variable_get to access the instance variable
@textField; we could now for example tweak the origin or size of the frame,
alter its attributes, or anything else we would like to do.
Uninitialized constant NSSQLiteStoreType
If you start a new RubyMotion project and forget to add the Core Data framework to your Rakefile before you build/run the app then even if you update your Rakefile you are still likely to get NameError exceptions for Core Data types, e.g.
1 *** Terminating app due to uncaught exception 'NameError',
2 reason: 'app_delegate.rb:19:in `initialise_core_data_stack':
3 uninitialized constant AppDelegate::NSSQLiteStoreType (NameError)
The solution in almost all cases should just be that you need to run rake
clean whenever you change the list of frameworks you load into your app. On
the next build all names should be resolved as you would expect.
Undefined method `viewWillAppear’
This error could occur, and cause a crash in your application, if you have
attempted to override a method such as viewWillAppear as follows:
1 class MyViewController < UIViewController
2 def viewWillAppear
3 # Your code
4 end
5 end
This can cause the RubyMotion runtime to complain that MyViewController has
no viewWillAppear method. As you have just defined one that doesn’t sound
quite right.
What the error message is really saying is that it can’t find
viewWillAppear, and the reason for that is that our definition above is
shadowing the one that the runtime would like to invoke, because it is
looking for viewWillAppear(animated).
As such, to fix this we should be sure to override viewWillAppear(animated)
and not the bare method viewWillAppear, thus changing our code to be:
1 class MyViewController < UIViewController
2 def viewWillAppear(animated)
3 # Your code
4 end
5 end
Other Errors and Crashes
Have you updated RubyMotion? If so, be sure to run rake clean in the shell
before continuing.
If you are encountering errors which you can find no reference to online you
might have discovered a bug; check the RubyMotion changelog for a reference
to it and try updating to the latest version (followed by a rake clean) to
see if that fixes it.
If you are still having problems then there is the RubyMotion Google Group, RubyMotion Support or you are very welcome to get in touch with me and I will do my best to help.
- One caveat is that RubyMotion is essentially an implementation of Ruby 1.9 which integrates tightly with iOS and OSX. As such you may miss some features that Ruby 2.x brings, and it has also been customised slightly to make working with the Cocoa libraries easier.↩
- This is a convention of Ruby rather than RubyMotion so you can use this in any of your own classes to customise their initialisation behaviour.↩