Componentix logo

Componentix blog

Here we write some random thoughts and articles about software development: Java, Grails, Node.js, iPhone, iPad and more.

Not so Swift – implementing transducers in Apple's new language

Motivation

Clojure's transducers represent an elegant and high-efficient way to transform data. JS implementation fared well, so I decided to try implementing them in Swift as well.

Examples

transduce(
    map({$0 + 1}) |>
    filter({$0 % 2 == 0}) |>
    map({$0 * 2}), append, [], [1, 2, 3, 4, 5])

// [4, 8, 12]

Code above is roughly equvivalent to following code with regular map / filter calls:

[1, 2, 3, 4, 5]
    .map({$0 + 1})
    .filter({$0 % 2 == 0})
    .map({$0 * 2})

Problems with Swift

Types. Swift is strongly typed so we get function signatures like this one:

func transduce<AccumType, ElemType1, ElemType2> (
        tfn : Transducer<AccumType, ElemType1, ElemType2>,
        rfn : (AccumType, ElemType2) -> AccumType,
    initial : AccumType, arr : [ElemType1]) -> AccumType]

I doubt anyone would find it nice.

Performance is even bigger problem for now. Currently it is anything but ready for production use.
As tested on Xcode Version 6.1.1 (6A2008a), it is at least 100x worse than standard map / filter chain.

Further info

See transducers implementation in this GitHub repo.

Hosted CI: new features and pricing update

Hosted CI is a hosted continuous integration service (developed by me) which is specifically tailored for iOS and Mac developers.

Since the launch of Hosted CI private beta we’ve added some useful features:

As you may have noticed – Hosted CI now has own blog where I post feature updates and some useful tips for developers.

Note that we also have updated our pricing plans.
There is a new Indie plan which is only $19/month + Max plan now costs only $199/month.

BTW, if you don’t have access to private beta yet or have any problems with it – write to ask@hosted-ci.com

Debug usage of Objective-C weak properties with KVO

I’ve recently stumbled upon Mike Abdullah’s blog post which has raised an interesting issue. When ARC is used, weak properties can be set to nil by the runtime. However if you register for KVO notifications using addObserver method, you won’t get notified of it. This is interesting, as it basically breaks KVO compliance. It is also worth noting that other updates of such properties still result in notifications.

Mike proposed that debugging code can be injected to check for the weak properties used with addObserver. I’ve decided to implement such code:

#import <objc/runtime.h>

void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL)
{
    Method origMethod = class_getInstanceMethod(c, origSEL);
    Method overrideMethod = class_getInstanceMethod(c, overrideSEL);
    if (class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
        class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    } else {
        method_exchangeImplementations(origMethod, overrideMethod);
    }
}

@implementation NSObject (KVOWeakPropertyDebug)

+ (void)load
{
    MethodSwizzle(self, @selector(addObserver:forKeyPath:options:context:), @selector(_addObserver:forKeyPath:options:context:));
}

- (BOOL)_isWeak:(NSString *)keyPath
{
    // TODO: Support complex keyPath variants
    objc_property_t property = class_getProperty(self.class, keyPath.UTF8String);
    if (property) {
        return property_getAttributes(property)[3] == 'W';
    }

    return NO;
}

- (void)_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
{
    if ([self _isWeak:keyPath]) {
        NSLog(@"WARNING: observing '%@' property, which is weak and so isn't fully KVO-compliant", keyPath);
    }

    [self _addObserver:observer forKeyPath:keyPath options:options context:context];
}

@end

Basically it is a category on NSObject that replaces addObserver method with own implementation using method swizzling. It checks whether observed key corresponds to weak property and logs a warning in such case, then just calls original implementation.

For convenience grab complete code as Gist.

Shameless plug

Check out our new service for iOS developers – hosted continuous integration.

Customize UITableViewCell background for grouped table view using UIBezierPath

When using UITableView in iOS apps quite often you’d like to customize its design. In particular it is typical to change background color of cells and color of separators. It is usually trivial enough with plain style table views, however may get tricky when you have grouped style table view.

The problem is that if you change backgroundColor property of a cell in a grouped table view you don’t get expected result. So the solution is to change backgroundView of a cell instead. Quite common technique is to use images and so UIImageView for the purpose. However if you want to keep standard look of cells but just change background color and border color it isn’t convenient.

So I’ve createad a reusable background view for this purpose. Thanks to UIBeizierPath class its implementation is trivial, basically main code is drawRect: method:

- (void)drawRect:(CGRect)rect
{
    CGRect bounds = self.bounds;
    UIBezierPath *path;
    if (position == CellPositionSingle) {
        path = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:kCornerRadius];
    } else if (position == CellPositionTop) {
        bounds.size.height += 1;
        path = [UIBezierPath bezierPathWithRoundedRect:bounds
                                     byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
                                           cornerRadii:CGSizeMake(kCornerRadius, kCornerRadius)];
    } else if (position == CellPositionBottom) {
        path = [UIBezierPath bezierPathWithRoundedRect:bounds
                                     byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
                                           cornerRadii:CGSizeMake(kCornerRadius, kCornerRadius)];
    } else {
        bounds.size.height += 1;
        path = [UIBezierPath bezierPathWithRect:bounds];
    }

    [self.fillColor setFill];
    [self.borderColor setStroke];
    [path fill];
    [path stroke];
}

Using the code is simple, it goes like this:

- (void)drawRect:(CGRect)rect
{
    CGRect bounds = CGRectInset(self.bounds,
                                0.5 / [UIScreen mainScreen].scale,
                                0.5 / [UIScreen mainScreen].scale);
    UIBezierPath *path;
    if (position == CellPositionSingle) {
        path = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:kCornerRadius];
    } else if (position == CellPositionTop) {
        bounds.size.height += 1;
        path = [UIBezierPath bezierPathWithRoundedRect:bounds
                                     byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
                                           cornerRadii:CGSizeMake(kCornerRadius, kCornerRadius)];
    } else if (position == CellPositionBottom) {
        path = [UIBezierPath bezierPathWithRoundedRect:bounds
                                     byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
                                           cornerRadii:CGSizeMake(kCornerRadius, kCornerRadius)];
    } else {
        bounds.size.height += 1;
        path = [UIBezierPath bezierPathWithRect:bounds];
    }

    [self.fillColor setFill];
    [self.borderColor setStroke];
    [path fill];
    [path stroke];
}

As a result you’ll get something like here:

Note that by using [UIColor colorWithPatternImage:] you can use not only solid colors but textures or gradients as cell background.

Full code is available as Gist, feel free to fork it.

Scary Colors – coloring book app for iPad

We’ve been long developing iOS apps for various clients and now finally released something own in the AppStore. It’s a coloring book for children, dedicated to Halloween theme.

There is a lot of similar apps, however we have some unique feature, that I wanted since I was child – color stays inside of lines when painting :)

See it here: http://happycolorsapp.com

Tags: ipad ios kids
Following e-mail is only for robots (never send anything to it, or you would be blacklisted): botsonly@componentix.com