iOS Logic Tests with CocoaPods and RestKit

I wanted to create for my RestKit mappings simple tests to get all the complicated relation mappings correct. First I tried it with usual tests but soon gave up because they start the whole application which made the tests quite slow and network dependent.

So I remembered the possibility of creating logic tests which require only a small testbed. After some time of unsuccessful attempts I remembered, that using CocoaPods might have an impact on the newly created Target for the logic tests. So I had to set the CocoaPods configuration for the new target in the project configuration.

But still it was not working because the linker had problems in finding my own classes. I checked everything: Imports, target dependencies, associated targets of the class files, header search paths, etc. But nothing seemed to help.

Until I found a little bit strange solution on the net which did the trick:
Setting the “Bundle Loader” and “Test Host” fields in the build settings:

Bundle Loader = $(BUILT_PRODUCTS_DIR)/<identifier>.app/<identifier>
Test Host     = $(BUNDLE_LOADER)

After this it worked fine. But as far as I understood it the idea of logic tests is not to start the full simulator and application. Maybe someday I will find out.

SWT Sashes with minimal size

A cool feature of SWT are sashes. They are ideal for creating flexible editors and views. But they have one major drawback (as do all SWT components). There is no way to set a minimal size on controls which the sash would use to calculate its range to move around.

This is one of the features I miss most from Swing.

There is of course the self made way and thats what I show in the following code examples.
First we need to create the content with the layout:

// Our member variables:
Composite firstPart;
Sash sash;
Composite secondPart;

private void createContent(Composite parent, FormToolkit toolkit) {
parent.setLayout(new FormLayout());
firstPart = toolkit.createComposite(parent);
createFirstPart(firstPart); // This method creates buttons, labels what ever inside this composite

sash = new Sash(parent, SWT.HORIZONTAL);

secondPart = toolkit.createComposite(parent);
createSecondPart(secondPart); // Same as above

FormData firstFormData = new FormData();
firstFormData.left = new FormAttachment(0, 0);
firstFormData.right = new FormAttachment(100, 0);
firstFormData.top = new FormAttachment(0, 0);
firstFormData.bottom = new FormAttachment(sash, 0);
firstPart.setLayoutData(firstFormData);

FormData sashFormData = new FormData();
sashFormData.left = new FormAttachment(0, 0);
sashFormData.right = new FormAttachment(100, 0);
sashFormData.top = new FormAttachment(50, 0); // This will place the sash in the middle
sash.setLayoutData(sashFormData);

FormData secondFormData = new FormData();
secondFormData.left = new FormAttachment(0, 0);
secondFormData.right = new FormAttachment(100, 0);
secondFormData.top = new FormAttachment(sash, 0);
secondFormData.bottom = new FormAttachment(100, 0);
secondPart.setLayoutData(secondFormData);
}

With this we will get two parts separated by a horizontal sash. The two composite create methods just create their content and set the composites layout. Preferably a grid layout with grabs space.

But it’s still possible to drag the sash over the content of either part. Assume we have a table with some buttons beside it in the first part: this will be a serious problem. The table will adjust its size if we make the first part bigger, but if we make it smaller there is a point where the content will vanish under the sash (or more exactly under the second part) and the scrollbar of the table might not even appear because the composite and therefore the table does not get smaller.
So we do actually have a minimal size of the composite but which no one respects. Neither the sash or any other control.

So we have to adapt to changes of the sash position as well as changes to the size of the surrounding composite. Therefore we have to listen to either changes of the sash position or changes to the control and do something to the layout:

sash.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
layoutSash(e);
}
}
parent.addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
layoutSash(null);
}
}

private void layoutSash(Event e) {
FormData sashFormData = (FormData) sash.getLayoutData();
Rectangle sashRect = sash.getBounds();
Rectangle workAreaRect = sash.getParent().getClientArea();

int totalHeight = workAreaRect.height;
int minimalSecondPartHeight = calculateMinimalHeight(secondPart).;
int absoluteSashMinY = calculateMinimalHeiht(firstPart) + 5;

sashFormData.top.numerator = 0; // As we use offsets from now on we must set the numerator back to zero

if (e != null) { // if we call this from a sash change:
int maxY = totalHeight - minimalSecondPartHeight;
if (e.y <= absoluteSashMinY) {
e.y = absoluteSashMinY;
sashFormData.top.offset = absoluteSashMinY;
} else if (e.y >= maxY) {
e.y = maxY;
sashFormData.top.offset = maxY;
} else {
sashFormData.top.offset = e.y;
}
} else {
if (firstPart.getBounds().height < absoluteSashMinY) {
sashFormData.top.offset = absoluteSashMinY;
}
if (this.entriesWidget.getBounds().height < minimalSecondPartHeight) {
sashFormData.top.offset = totalHeight - minimalSecondPartHeight;
}
}
this.parent.layout(true, true);
}

Now all we have to do is to create a sensible implementation of the calculateMinimalHeight and we have it.

SWT ScrolledComposite not visible (until it’s parent is satisfied)

A ScrolledComposite has some special requirements to its parent, which is quite unusual in OOP with composite patterns. The content should be parent agnostic.

The ScrollComposite absolutely refuses to work properly if the parent composite does not have the FillLayout.

Hopefully it took you not the two hours I have spent until finding this undocumented fact.