shinobiforms userguide


This document provides an overview of the shinobiforms control. It describes the features of the control and its associated concepts.

shinobiforms provides a quick and effective way to capture your user’s data in an iOS application. Once your user has entered their data into the fields in a form, the control allows you to access that data.

If you simply want to get up and running, follow the , alternatively, for a more detailed description of how forms work and the features they present, head over to the shinobiforms Control Overview.

shinobiforms control overview


Form model objects can exist independently of a view, although model objects will need a view to represent them if you are to collect data from the users of your application (see Views). The fact that model objects can exist without views means you can store them, create them, and pull information from them without caring about the view hierarchy.


A ShinobiForm is a model object of a form. A form is a collection of fields that are conceptually linked composing a single unit of input for submission. The model needs to be represented by a view so it can be added to your view hierarchy for user interaction (see SFormView). A form has multiple SFormSection model objects that represent groupings of SFormFields within the form.

Adding Sections

You can add sections to a ShinobiForm by assigning an NSArray of SFormSection objects to the sections property.

ShinobiForm *form = [ShinobiForm new];

SFormSection *section = [SFormSection new];
form.sections = @[section];
Submitting Data from The Form

A ShinobiForm supports submitting its data to a delegate. To do this, set the delegate property on the form which can be an instance of any class which adopts the SFormDelegate protocol. Then, call the submit method on the form. This method will validate the form and then notify the delegate.

To add a submit button to your form see the section Adding a Submit Button.


An SFormSection is a model object of a section. A section is a collection of fields that are grouped and laid out separately to fields in other sections. The model needs to be represented by a view so it can be added to your view hierarchy for user interaction (see SFormSectionView).

Adding Fields

You can add fields to an SFormSection by assigning an NSArray of SFormField objects to the fields property.

SFormField *field = [SFormTextField new];
section.fields = @[field];


An SFormField is a model object of a field. The model needs to be represented by a view so it can be added to your view hierarchy for user interaction (see SFormFieldView).

A field object holds a value of a specific type. This type depends on the type of field you are using - check the specific fields documentation for further information. Setting the value on a field will cause the validators contained with the field’s validators array to validate the field. This will in turn update the field’s isValid status. Any failing validators will be added to the currentlyFailingValidators array providing an easy way to grab error messages from the failing validators.

For a list of the available field model subclasses see the documentation for SFormField.


The SFormField class has a validators property which holds objects conforming to the appropriate validator protocol (SFormTextFieldValidator, SFormNumberFieldValidator, SFormChoiceFieldValidator etc.). These objects are responsible for validating the contents of a field’s value property. An SFormField will validate whenever the value property changes.

You can specify the type of validation you want on your field by assigning validators like so:

SFormTextField *field = [SFormTextField new];
field.validators = @[[SFormTextFieldNotEmptyValidator new]];

We provide a number of validators out of the box which can be initialized either directly as shown above, or through our validation utility classes.

field.validators = @[[SFormTextFieldValidators notEmpty]];

We have created a code sample which demonstrates this: ValidatingTextField.xcodeproj

You can create validators by directly instantiating the validator classes but we recommend using the validator utility class for each field type. These validators provide a ‘menu’ of our provided validators, as well as convenience methods for common validation use cases. Below is a list of the validation utility classes.

Comparison Validators

You may find you need to validate a field by comparing it to the value of another field. For example, a ‘maximum’ field where the value must be larger than a ‘minimum’ field. To make these validation cases easier, we’ve provided validators that do just this.

To validate a field’s input against another field, simply create the validator by providing the field to compare against and the required result, then add the validator to the field.

SFormNumberField *minPriceField = ...;
SFormNumberField *maxPriceField = ...;

SFormNumberFieldComparisonValidator *lessThanMax = [SFormNumberFieldValidators compareWithNumberField:maxPriceField validResult:SFormComparisonRuleLessThanOrEqual];
minPriceField.validators = @[lessThanMax];

SFormNumberFieldComparisonValidator *greaterThanMin = [SFormNumberFieldValidators compareWithNumberField:minPriceField validResult:SFormComparisonRuleGreaterThanOrEqual];
maxPriceField.validators = @[greaterThanMin];

The SFormNumberFieldValidators utility class provides a much easier way to validate a minimum and a maximum field - the above code snippet can be simplified down to the following.

SFormNumberField *minPriceField = ...;
SFormNumberField *maxPriceField = ...;
self.minMaxGroup = [SFormNumberValidators minMaxGroupForMinNumberField:minPriceField maxNumberField:maxField];
Validation Groups

The SFormFieldGroup can be used to ensure that when one field updates other fields also re-validate - useful when one field is validating against the contents of another. (We use field groups internally to implement minimum & maximum field validation as seen on the validator utilities.) If one field in the validation group validates, every field in the group will also validate.

To set up a validation group all you need to do is create one, add some fields.

SFormFieldValidationGroup *validationGroup = [SFormFieldValidationGroup new];
validationGroup.fields = @[field1, field2];
self.myValidationGroup = @[validationGroup];

Note that you need to keep a strong reference to your validation groups.


Without a view representing model objects, your forms won’t be able to collect data from your users. The view is what your application’s users will be interacting with.

Each model object has a subclass of UIView to visually represent it.

These views observe the model objects and ensure that they keep in sync when the model updates. They also make sure that they keep the model up to date when your users enter data into the views. (Note that the model will not update to reflect programatic changes on the view.)

Connecting the View and Model

The easiest way to set up a form is to use one of our provided view builders (see View Builders). However, if you have a view you have created, you can easily connect it up with your model object by assigning the model object to the view and adding an appropriate converter (see Converters). The view takes care of all observation and synchronizing.

SFormTextField *model = [SFormTextField new];
SFormTextFieldView *view = [SFormTextFieldView new];

// Add a converter to the view.

view.model = model;

Note that when assigning a model to a view, the model will synchronize with any values already set on the model, as well as any values set on the model from then onwards. For example, the two following code snippets are functionally equivalent.

// Snippet 1
SFormTextField *model = [SFormTextField new];
SFormTextFieldView *view = [SFormTextFieldView];

// Add a converter to the view.

view.model = model;

model.value = @"Hello World!"; // Field updates to display the model's new value.

// Snippet 2
SFormTextField *model = [SFormTextField new];
model.value = @"Hello World!";

SFormTextFieldView *view = [SFormTextFieldView];

// Add a converter to the view.

view.model = model; // Field updates to display the model's value.

View Builders

View builders provide a simple way to build a view hierarchy for any of your model objects. All you need to do is provide your model to one of these builders and it will spit out a ready to use view hierarchy. You will have already seen this in the Creating a Simple Form section. An example of building a form view for a form model is given below.

SFormView *formView = [[SFormFormViewBuilder new] buildViewFromModel:self.form];

There are three view builders provided for you, SFormFormViewBuilder, SFormSectionViewBuilder, and SFormFieldViewBuilder for building form, section and field views respectively.

When providing a model object to one of the previously mentioned view builders, the view builder will carry out three steps.

  1. The view builder will create a suitable view for the provided model object.
  2. The view builder will assign the provided model object to the view as described in Connecting the View and Model.
  3. The produced view will be sized to fit by calling sizeToFit on the view.

Warning: In the case of the SFormViewBuilder and the SFormSectionBuilder the views will be built recursively downwards. For example, passing a form model through an SFormViewBuilder will create views for the form model’s section model, and the section model’s field models.


An SFormView is a visual representation of a ShinobiForm model object. The SFormView observes changes to the ShinobiForm object assigned to its model property.

For a list of properties the SFormView observes on its model, check the SFormView documentation.

Warning: Modifying the sections array will cause any section views on the form to be replaced.

Adding a Submit Button

To add a submit button to your form, all you need to do is set a UIButton as your SFormView’s submitButton property. It will automatically have the parent form added as a target, calling submit on touch up inside. We also provide a UIButton subclass, SFormSubmitButton, which is styled to match our default form style.

SFormSubmitButton *button = [SFormSubmitButton new];
[button sizeToFit];
formView.submitButton = button;

For advice on positioning the submit button see Layout.

For an example of using a submit button in a form, take a look at the SubmitForm.xcodeproj sample project.


An SFormSectionView is a visual representation of a SFormSection model object. The SFormSectionView observes changes to the SFormSection object assigned to its model property.

For a list of properties the SFormSectionView observes on its model, check the SFormSectionView documentation.

Warning: Modifying the fields array will cause any section views on the form to be replaced.


An SFormFieldView is a visual representation of a SFormField model object. There are a number of SFormFieldView subclasses provided to represent different field model object subclasses. The SFormFieldView is a UIView subclass that is made up of the following components:

  • label: This is a UILabel which can be used as the title of your field.
  • requiredLabel: A UILabel can be used to indicate to the user that the field is required.
  • inputElement: A UIView allowing data entry.
  • errorLabel: A UILabel that can display an error message upon failed validation.

For a list of the available view subclasses see the SFormFieldView documentation.

Disabling a Field

There may be times when you want a field to be disabled. To do this you can simply set the field view’s enabled property to NO.

fieldView.enabled = NO;

This will change the field to look inactive, giving it a faded appearance as well as disallowing user input.


The SFormFieldView observes changes to the SFormField object assigned to its model property. For example, SFormFieldView observes the value property on it’s assigned model. Updating the model’s value property will update the value displayed in the field as shown below.

SFormTextField *model = [SFormTextField new];
SFormTextFieldView *view = [SFormTextFieldView new];
view.model = model;

model.value = @"Hello World!";

The above snippet will change the text value of the field view’s UITextField to “Hello World!”.

There are a few properties that the field view observes, check the SFormFieldView’s documentation (and the documentation of any SFormFieldView subclasses you are using) for a full list.


The type of a field view’s input can differ from the type or format of it’s model’s value property - this is where the converter plays its role. A converter is responsible for converting between these two differing types or formats and is an object conforming to SFormFieldModelViewConverter.

An example of where the type is the same, but the format may differ is an SFormTextFieldView with an underlying SFormNumberField. In this case the user may input any characters offered by the pop-up keyboard into the inputElement of the SFormTextFieldView, but the SFormNumberField needs to receive an NSString for its value property that only contains numbers or valid grouping/decimal separators. This requirement is often described as an input mask, and can be achieved with a converter.

To set up a view without using the builders you need to first create your own view.

SFormTextFieldView *view = [SFormTextFieldView new];

Then we connect up the model as described in Connecting the View and Model.

view.model = [SFormNumberField new];

You then need to assign an appropriate converter. In this example we’ll need a converter that masks non-numeric characters in an NSString on the view side and passes this to the model side. You could write your own, by implementing a class that conforms to SFormFieldModelViewConverter, but we’re going to use the provided SFormNumberFieldConverter which already has this functionality.

view.converter = [SFormNumberFieldConverter new];

You now have a field view that takes text input of any format, a converter which strips non-numeric characters (aside from grouping/decimal separators), and a model that will receive only numeric strings from the converter.

The SFormFieldModelViewConverter defines two methods:

  • viewValueFromModel: - this method is responsible for converting from the model’s type/format to the type/format needed by the view.
  • modelValueFromView: - this method is responsible for converting from the view’s type/format to the type/format needed by the model.

By implementing these two methods you have ultimate power over view/model compatibility. Using different converters, or even converters you’ve written yourself, you can create new field combinations using the model objects and views we provide out of the box - you can even combine them with your own custom views!

We have created a code sample which demonstrates a converter: Converter.xcodeproj


All view objects (SFormView, SFormSectionView and SFormFieldView) have a layout property containing a layout object.

This layout is delegated to for the view’s layoutSubviews and sizeToFit implementations.

Assigning an object to this layout property provides an easy way to change the layout of a view without subclassing. To change a view’s layout you can create your own concrete implementation of the relevant protocol and assign it to the view’s layout. For information on our out of the box layouts, please see the layout protocols for a list of concrete implementations (SFormLayout, SFormSectionLayout and SFormFieldLayout).

It is possible to write your own layout behaviors by creating classes that conform to the above layout protocols. These objects can them be assigned to the relevant view’s layout property.

ShinobiForm *formView = [ShinobiForm new];
formView.layout = [MyTotallyAwesomeLayout new];

There are two other alternatives ways to lay out a field.

  1. Subclass the relevant view and implement layoutSubviews.
  2. Nil the view’s layout object and set the frames of the view’s subview yourself. Here’s an example sizing a field this way:
SFormTextFieldView *view = [SFormTextFieldView new];
view.layout = nil;

view.frame = CGRectMake(0, 0, 300, 50);
view.inputElement.frame = CGRectMake(0, 0, 200, 50);

Adding the Form to a Scroll View

Adding the form to the scroll view is done exactly the same as you would with any other view. However, shinobiforms provides a useful class that increases the usability of a form in a scroll view, SFormScrollViewManager. The SFormScrollView manager modifies a given scroll view in response to keyboard events. All you need to do is set up your scroll view manager like so.

self.scrollViewManager = [[SFormScrollViewManager alloc] initWithScrollView:myScrollView];

When the keyboard appears, the correct amount of padding will be added to the scroll view’s content inset so that your users can scroll to the bottom of your scroll view to see fields that would otherwise be covered by the keyboard.

For an example of using the scroll view manager, take a look at the FormInScrollView.xcodeproj sample project.


You can add a toolbar above the keyboard whilst editing a SFormField by assigning a UIView conforming to the SFormNavigationToolbar protocol to your form view’s keyboardToolbar property. By default this toolbar will be an instance of SFormToolbar which provides two buttons on the toolbar that allow users to easily navigate between fields.

When fields are added to the form they will have their inputAccessoryView set to this the value of keyboardToolbar. If you’d like to remove the toolbar you can simply assign nil to the keyboardToolbar property.

formView.keyboardToolbar = nil;

As mentioned previously, the default keyboard toolbar is an SFormToolbar. This toolbar will provide two buttons, a previous button (a minimal arrow pointing to the left) and a next button (a similar arrow pointing to the right). These arrows allow users to navigate to the field previous or next to the currently selected field. If you are at the very first or last field, the previous or next button will be disabled respectively.

Creating a Custom Toolbar

The SFormToolbar subclasses UIToolbar, for basic customization you can simply modify or add UIBarButtonItem objects in the toolbar’s items array. If you’re looking for heavier customization and you don’t want to hook into our built in navigation functionality then you can directly replace the keyboardToolbar property on your form. However, if you’re hoping to keep our navigation functionality then you’ll need to understand a little bit about how our toolbar communicates with the form and vice versa.

SFormToolbar conforms to the SFormNavigationToolbar protocol. To hook into our navigation you’ll need to implement the two methods defined by this protocol.

  • The method setFieldNavigator:.
  • The method fieldView:becameFirstResponderHasPrevious:hasNext:.

The fieldNavigator gives you an object you can send messages to, telling the form to focus on a new field. As you can see, the object passed into the method setFieldNavigator: conforms to the protocol SFormNavigator which defines three methods, focusPreviousField, focusNextField (these methods will do nothing if there is no previous/next field) and dismissField.

When a new field view becomes first responder, the toolbar will have the method fieldView:becameFirstResponderHasPrevious:hasNext: called on it. This method tells the toolbar what field was selected, and whether there are any fields previous or next to it. For example, we could display information specific to the selected field somewhere on our toolbar, or enable/disable the next and previous buttons as we get to the beginning/end of the form.

Creating a ShinobiForm with XML

It is possible to write the model part of your form in XML. This can then be parsed by an SFormXMLParser to produce a ShinobiForm at runtime.

To create ShinobiForms from XML you will need to first add the ShinobiForms_XSD.xml file to your application’s bundle as per Adding shinobiforms Resources.

It is not currently possible to write the view part of your form in XML, but the SFormFormViewBuilder can help you to easily generate a view hierarchy to represent the ShinobiForm output from the parsing of XML. See View Builders for more information on this.

See the FormFromXML.xcodeproj sample for an example of how a form can be constructed from XML.

Writing XML Forms

The best way to ensure you are writing XML that our API can parse is to adhere to the XSD (XML Schema Definition) file (ShinobiForms_XSD.xml) that is embedded in our ShinobiForms.framework.

See the FormMeta.xml file in the FormFromXML.xcodeproj sample for an example of a valid XML file that can be parsed to a ShinobiForm.

XML Elements

The following is a list of XML elements and the ShinobiForm objects they map to:

Parsing XML Forms

Our API handles XML as NSStrings. You can parse your xml via the following:

NSString *xml = //get your xml as an NSString
ShinobiForm *form = [[SFormXMLParser new]formFromXml:xml

Validating XML Forms

As seen in the Parsing XML Forms code example, the method for producing a ShinobiForm from XML (formFromXml:xmlEncoding:xsd:xsdEncoding:) has an XSD parameter. This is used to validate that the XML meets the schema definition before parsing begins. Passing nil for this parameter results in us falling back to using the ShinobiForms_XSD.xml file in your application’s main bundle.

It is possible to validate XML without then parsing it into a ShinobiForm:

NSString *xml = //get your xml as an NSString
BOOL isValid = [[SFormXMLParser new]isValidXml:xml


shinobiforms uses a strings file to allow you to localize the strings used within your forms. The form looks for a strings file named ShinobiForms.strings within your application’s main bundle. You can add this to your main bundle by following Adding ShinobiForms Resources. Once this is done you should then be able to add extra strings for the locales you wish to support.

Adding ShinobiForms Resources

You can add ShinobiForms resources to your application’s bundle. You can do this by dragging the resource/file, found within your ShinobiForms.framework bundle, into your project’s navigator.