Building Xcode projects with Ruby

image

Image by vandalog

Continuous integration is a powerful tool in any iOS developers toolchain as it allows you to automate a large portion of your workflow and ensures projects stay healthy and running. One problem with Xcode is that the command line interface can be very complex and undocumented at times which makes continues integration tricky. 

This is why i’ve created yolo, a RubyGem which provides a Ruby interface to Continuous Integration build tools. yolo is currently geared towards the Xcode toolchain and iOS development.

yolo allows you to run a number of continuous integration tasks and is best implemented with an installation of Jenkins.

Examples of tasks yolo can complete for you are:

  • Building Xcode projects
  • Running OCUnit & Kiwi unit tests and generating reports
  • Running Calabash integration tests and generating reports
  • Packaging iOS IPA files and deploying them to external services
  • Sending notification emails
  • Running tasks on each new git tag or commit

Yolo on Github

Yolo on RubyGems

3 notes 
Tags: ruby xcode buildtools continuous integration jenkins ios

Converting svn repositories to git with Kafka

image by christiaan_tonnis 

SVN really sucks, every time i use it i find myself rolled up in a ball on the floor crying after about 20 minutes. And unfortunately for me, some of the very old projects i work on now and again are based in SVN repositories. 

The great project svn2git seemed like a dream come true when i stumbled upon it, although I found out pretty quickly that it just doesn’t seem to want to play ball with repositories hosted on unfuddle, which the majority of our projects are. 

This is where the idea for kafka came along, I needed a quick and hassle free way to convert our old SVN repositories to git, for sanity and general productivity. Loosely based on svn2git kafka is a tiny little ruby gem which uses the power of git-svn to convert svn repositories to git.

To give Kafka a try, simple install the gem with rubygems:

gem install kafka

Kafka is in it’s pretty early stages, as in version 0.0.2, so it does have it’s limitations. The largest being it will only work with SVN repo’s using the standard SVN repo layout:

- trunk
- branches
- git

For a step-by-step guide and more information you’ll want to head to the github for the project. 

Kafka on Github 

1 note 
Tags: git svn svn2git svn git

Introducing Laterflix - Watch later for Netflix

I spend a few hours today putting together a Chrome extension i’ve been needing for a while now. I always found i spotted films on Netflix that i wanted to watch but not right now. Netflix didn’t have any sort of functionality that would allow me to save films to a list for later so i thought i would build this functionality into Netflix.com with a Chrome extension.

Laterflix add’s watch later functionality to Netflix.com allowing you to save movies and view them at a later date. 

Ever spot a movie you’ve been meaning to watch when browsing Netflix.com but don’t have the time to watch it right then? Laterflix allows you to save it for later so that you don’t miss out. 

* Simply press the watch later icon underneath each movie to save them to your watch later list.

* Laterflix adds a new ‘Saved’ menu option to Netflix.com which allows you to browse and view your saved movies. 

* Remove items from your saved list just as easily as you added them.  

Laterflix is 100% free so there’s no excuse not to try it out! It’s also open source so feel free to fork it on Github.

Tags: Netflix extension chrome watch later

Fetching every row of a table with Parse and PFQuery

Recently i came across a problem when using the Parse iOS SDK. Unknown to me, the Parse PFQuery object will only return 100 results by default. Which unfortunately, i found out the hard way when one of my apps stopped returning results when the table hit the 100 rows mark. As the Parse documentation says hidden away somewhere:

You can limit the number of results by setting limit. By default, results are limited to 100, but anything from 1 to 1000 is a valid limit:

So what if we want more than 100 results? This question on the Parse support site has a great answer from Héctor Ramos on how to return all the rows in a table with a PFQuery. Although.. as great as the answer is, it only really points you in the right direction. And does not supply a final solution to fetch every result using PFQuery. 

I came up with a little sollution using a recursive block, which will use a PFQuery object to query Parse until every result has been returned.

+ (void)findAllObjectsWithQuery:(PFQuery *)query withBlock:(void (^)(NSArray *objects, NSError *error))block
{
    __block NSMutableArray *allObjects = [NSMutableArray array];
    __block NSUInteger limit = 1000;
    __block NSUInteger skip = 0;
    
    typedef void  (^FetchNextPage)(void);
    FetchNextPage __weak __block weakPointer;
    
    FetchNextPage strongBlock = ^(void)
    {
        [query setLimit: limit];
        [query setSkip: skip];
        
        [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
            if (!error)
            {    
                // The find succeeded. Add the returned objects to allObjects
                [allObjects addObjectsFromArray:objects];
                
                if (objects.count == limit) {
                    // There might be more objects in the table. Update the skip value and execute the query again.
                    skip += limit;
                    [query setSkip: skip];
                    // Go get more results
                    weakPointer();
                }
                else
                {
                    // We are done so return the objects
                    block(allObjects, nil);
                }
                
            }
            else
            {
                block(nil,error);
            }
        }];
    };
    
    weakPointer = strongBlock;
    strongBlock();
        
}

So to use this method we can simply do the following:

PFQuery *query = [PFQuery queryWithClassName:@"myClassName"];

[ParseProxy findAllObjectsWithQuery:query withBlock:^(NSArray *objects, NSError *error) {
	if(!error)
	{
		NSLog(@"Loaded All Objects: %@",objects);
	}
}];

Easy!

Tags: Parse PFQuery iOS apple objective-c blocks

Liferaft: A Lighthouse iPhone App

A very long time ago i started working on an iPhone client for Lighthouse, a very useful bug tracking solution which i recommend you check out (no they are not paying me).

Last December i finally found some spare time to finish the app, which has been available on the app store since then. I wanted to keep it very simple and easy to use and will allow you to use Lighthouse while on the move, as they currently do not have a native iOS client.

Currently Liferaft allows you to do the following, all at the bargain price of £1.49:

* Create and edit projects
* Create tickets
* Comment on and update tickets
* Easily sort tickets by User, Milestone, Priority, Created and Modified date.
* Assign users and milestones
* Quickly and easily manage your lighthouse projects

Someday soon i will find some more time to add a ton of new features to it, even sooner if you go out and buy it! I’m currently waiting for an update with some minor bug fixes to be approved. But if you do find any bugs or have any feature requests, please drop me a line on the email address at the top of this page.

Tags: lighthouse liferaft ios apple iphone app iphone bug tracking bugs project management

Generating your own UDID

Update: I’ve since stumbled upon OpenUDID which is an even better solution.

Now that Apple are phasing out the use of UDID’s due to privacy reasons, developers are required to generate their own unique device identifiers. I’ve put together a quick method that you can utilize to generate a unique id and store it to the devices keychain using Apple’s KeyChainItemWrapper

- (NSString *)guid
{

    KeyChainItemWrapper *keychain = [[[KeychainItemWrapper alloc] initWithIdentifier:@"UDIDData" accessGroup:@"crossbow.com.alexfish.GenericKeychainSuite"] autorelease];
     
    NSString *guid = [keychain objectForKey:(id)kSecValueData];
         
    if(guid.length == 0)
    {
        CFUUIDRef uuid = CFUUIDCreate(NULL);
        CFStringRef uuidStr = CFUUIDCreateString(NULL, uuid);
        CFRelease(uuid);
        guid = [(NSString *) uuidStr autorelease];
         
        [keychain setObject:guid forKey:(id)kSecValueData];
    }
     
    return guid;
      
}

This method checks if a generated ID already exists on the device and if not simply generate one, store it to the keychain then return it. It’s also worth noting that Apple’s code has a memory leak at KeyChainItemWrapper.m:196

self.keychainItemData = [[NSMutableDictionary alloc] init];

Should be..

self.keychainItemData = [[[NSMutableDictionary alloc] init] autorelease];

Thanks Apple!

2 notes 
Tags: UDID Apple iOS iphone development iOS 5.0

Minimal Calculator App

An extremely minimal gesture based calculator, looks like they’ve seen how well Clear has done and applied the same ethos to the calculator.

Tags: Apps Calculator iOS Apple UX Design UI