Componentix logo

Componentix blog

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

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.

Custom calendar view for iPhone

When developing MTS Artguide app I needed to use calendar view. While there are existing implementations (Kal and TKCalendarMonthView from Tapku Library, they are quite limited. In particular they both replicate styling and functionality of iPhone Calendar app and there is basically no easy way to adjust them. In addition to this – only portrait view is supported in them. And I absolutely had to support landscape mode.

So I developed my own control. ios-calendar is a stylable month calendar view for use in iPhone applications. It uses Three20 framework heavily, especially for styling.

It’s default design is heavily inspired by MoMa iPhone app.

Info on usage and source code are available on GitHub: http://github.com/vgrichina/ios-calendar

Source code is provided under MIT license, feel free to fork it and use as you wish.

Shameless plug

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

Using JSONP with Three20

We use excellent Three20 framework in most of our iPhone projects. One of the great things provided by it is convenient framework for making HTTP requests to web services. There are plugins available to parse both JSON and XML responses. However for one of the projects I needed to parse JSONP response and I haven’t found any ready to use solution.

So I decided to make my own implementation of JSONP response parser, based on available TTURLJSONResponse class. Here it goes:

@implementation JSONPResponse

// This method is based on the same-named method in TTURLJSONResponse
// Note, that only SBJSON suport is left
- (NSError *) request: (TTURLRequest *) request processResponse: (NSHTTPURLResponse *) response
                 data: (id) data {

    // This response is designed for NSData objects, so if we get anything else it's probably a
    // mistake.
    TTDASSERT([data isKindOfClass: [NSData class]]);
    TTDASSERT(nil == _rootObject);
    NSError *err = nil;
    if ([data isKindOfClass: [NSData class]]) {
        NSString *json = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];

        // Remove JSONP wrapper

        json = [json stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSRange openingBracket = [json rangeOfString: @"("];
        NSRange closingBracket = [json rangeOfString: @")" options: NSBackwardsSearch];

        if (openingBracket.location != NSNotFound && closingBracket.location != NSNotFound) {
            json = [json substringWithRange:
                    NSMakeRange(openingBracket.location + 1, closingBracket.location - openingBracket.location - 1)];

            // Parse JSON
            _rootObject = [[json JSONValue] retain];
        }

        // Report error if failed to parse
        if (!_rootObject) {
            err = [NSError errorWithDomain: kTTExtJSONErrorDomain
                                      code: kTTExtJSONErrorCodeInvalidJSON
                                  userInfo: nil];
        }
    }

    return err;
}

@end

Full source code is available as Gist: https://gist.github.com/1052330

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