Friday, October 24, 2014

Making a numeric/pin pad with NSLayoutConstraints


NSLayoutConstraints are awesome. But like many cocoa technologies (strangely, all the ones that I like) the learning curve is fairly steep.

The goals was simple, I wanted to make a Numeric pin pad that would center itself in it's container view, while ensuring that all the buttons remained square, and aligned .... Ok, maybe not so simple.


Personally I hate resorting to changing the constraint priority, as I feel that most of the time it's a sign that your approaching the problem incorrectly. You can see a gist of the constraints below, ultimately I found the trick was this gem "-(>=1)-". By placing this between the outermost views and then pinning these to the superview, they provide the layout with the flexibility to meet all of it's requirements without having to adjust the superview or simply "explode".

Lastly, if your wondering why i've adopted this strange grouping mechanism inside my loop, I wanted the subview index have a 1-1 mapping with the button number, with out having to resort to setting tags. This way in the button handers I can look up the index of the sender in the subview collection, and know which button it is.

Like 99% of cocoa code, it's not concise. Disfrutarlo!

Monday, July 07, 2014

Future by Design

As a child I loved popular science magazine. Mainly because I was busy designing the future of space propulsion. Hint, it used "controlled" nuclear explosions.

However I've felt that since the 90's we (as a society) have lost our wondering quest for the next generation society. Today I discovered an inventor/futurist named Jacque Fresco. He's been pumping out ideas since before the second world war, some of which I think are brilliant, he also has some interesting views on society, and why it works as it does.
   

Tuesday, February 11, 2014

Filing Corporation Tax: CT600

I've been running my own UK Private limited company for a few years now. Because I'm cheap, I do my taxes myself. Usually from a location that would be considered glamorous by UK standards. As such calling the support line isn't really an option.

In recent years I've had a number of issues downloading the CT600 form. If you want to file independently you have to do it via this form, there is no alternative. This of course creates an issue if your nearing the deadline, and can't access the form.

If you happen to be having issues I have a single tip for you. Private browsing mode. Works for me every time.

Happy Tax filling day.

Tuesday, January 07, 2014

2014: Feliz Nuevo Año

A Kite Surfer in Cabo de La Vela, Colombia
While I doubt 2014 will mean that I suddenly start posting on a regular basis. For my millions of readers, Happy New Year.

Saturday, December 21, 2013

What a difference 3 years makes

In October of 2010 I came up with the bright idea to move to Sevilla, Spain.
Everything I knew about the City came from combination of wikipedia, Wikitravel & Google Earth. I packed my bag and got on a plane.

The sun shone, the drink flowed, I loved it.

But sadly, after only 6 weeks I decided to come home after a death in my Family. After 5 months back in England I had had enough, and set off again. Final destination unknown. This time I didn't come back for over 2 years.

Fast forward to today, 3 years later. I'm about to (try to) move to Bogota, Colombia. The situation is different this time around. I'm older (yay), I've seen a lot more of the world, I've actually visited the city before, and more importantly I can buy an Ice cream without resorting to Chinese.

What a difference 3 years makes.

Thursday, August 15, 2013

Vida en Venezuela - Parte 2, Caracas

With our stamps in hand, we re-entered colombia (illegally) and got our bags and supplies for the bus trip. The bus was supposed to leave Maicao for the border at 4pm were we would then change onto another bus and then head for the capital. We didn't leave 7:45pm.

As soon as the bus left the carpark, which was located between the Colombian and Venezuelan border checkpoints the driver opened the door to the cabin and announced that if we wanted to leave quickly he would need 400VEF (US$12) bolivars so we could skip the queue of other buses ahead of us at the border checkpoint. A lady in the front row stood up and took a collection among the passengers, there were no complaints, just people requesting change for smaller bills.

Once the collection was complete, she counted the cash in front of everyone, took out 400 and counted the remaining bills, and announced the total to the bus, handed off the 400 to the bus driver, put the rest in her bag and took her seat. Just like the driver promised we whizzed past the other buses and started on our way.

I don't know what it was about our driver but he constantly had the look of someone who had a gun to his head. His eyes were wild, and his thin frame didn't help him appear any more settled with his surroundings. In retrospect if I had to drive a bus in the middle of the night to a city with 2700+ murders a year I would be a little gaunt too.

The money that was left over from the initial collection was not for the lady, but for the buses "bribe fund". I discovered this at the next checkout when the driver opened the door and requested the remainder of the funds from the lady. At the subsequent checkpoint he made a another request for funds , with our initial fund being exhausted he started at the back of the bus and worked his way to the middle before deciding he had a enough "lubricant" for this particular situation.

Just before we crossed the longest concrete bridge in the world we were stopped again. This time a for what ever reason a bribe would not work. We were ordered off the bus, and our identification and visa stamps checked to ensure we were there legally.

After this point I became extremely paranoid, I split my cash across my bags and wallet, I hid my USD in my underwear, and prepared a "disposable" wallet with about $40 and some debit cards. I had heard stories of buses being hijacked in safer countries than here, but i had never felt so unsafe during my time in South America until now.

Throughout the rest of the night, every time the door would open, which it did often as it didn't lock properly I would prepare myself to be stormed by paramilitaries with AK47's.

After 15 hours or so I found myself at La Bandera Bus station in Caracas, where the walls are papered with Nationalist rhetoric, like the "people are the heart of the country" and "Chavez said Maduro should be the leader". After a quick costume change we made a quick attempt to get a refund for our return ticket to Maicao, but either the tiredness or the complete lack of good spanish meant that we failed to get it. After a brief sweep of the Station we determined that we could not get to the east of the country from La Bandera. I was tempted to use our fake reservation at a Hotel in Caracas, but at the same time I was cognisant of the fact that this was Caracas. So we did the clever thing and got in a unlicensed taxi and made our way to Terminal de Oriente.

Hector, our cab driver gave us the quick low down on the city. He works in Caracas, but doesn't live there as it's too dangerous. Instead he lives 45 minutes away in a suburb. Traffic during the week is awful, but this was a Sunday so it was fairly clear. He also showed us the most dangerous barrio in the city. 200 (USD$8) Bolivars later we arrived at Terminal de Oriente. We found a bus heading to the south-east of country, Vladimir was heading to Santa Elena, while I was going to Ciudad Bolivar. The ticket was 200 Bolivars, which doesn't quite make sense given that the taxi ride was so expensive, but hey it's USD$8. We had to wait for 4 hours before the bus left so we settled in with some tripe soup and roast chicken.

An hour into our wait, Vladimir discovered that there was flight to Rio from Caracas for US$100 after currency tricky was applied and made a mad dash for the airport. I charged my phone, bought some water, and continued to wait.

That was Caracas.

Thats a lot of lines

My Journey(s) of the last two years

I arrived back in England this past tuesday. Almost a year since I was last here, and well over 2 years since I left. It's been two days, and quite frankly I'm dreaming about leaving again.

Saturday, June 29, 2013

Unique objects with Core Data: Find and Create

I don't think it's a secret that I love Core Data. It's my opinion that the people who don't like it or use it are either very stupid or extremely smart.

There is one problem that has plagued me for years, how to ensure that when i'm perform imports I don't create duplicate objects. In reality the problem is fairly simple conceptually, you create a hash table, and then hash the Incoming objects to test for their membership in the set, Easy.

But if you believe in DRY, the problem is then making this unique constraint checking code modular and portable across projects, and different Core Data Models.

The first issue we need to is identify what property of a NSManagedObject should be unique relative to the rest of the greater set. We can achieve this by adding a class method to the NSManagedObject class

+ (NSString *)uniqueKeypath {
  return nil;
}


However, in an more advanced model there might be multiple properties that need to be evaluated to determine if an object is unique so …

+ (NSArray *)uniqueKeypaths {
  return nil;
}


It's important to note that since we are using Keypaths, we can actually evaluate the values of related entities.

Finding a Needle in a Haystack

Now it's time to make the magic happen. We apply the concept, we create a hash table, then lookup the unique value of the new objects in the table. If we get a 'hit', we don't do anything, if we 'miss' we create a new object. The sudo code is effectively.

FOR EACH object IN newObjects:

  IF NOT object IN allObjects:

    createObject(object)


The above is simplistic, but you get the point. However you should have made the observation, that if we do it exactly like this, it will not only take ages but we'll run out of memory long before we've began doing the comparison object if we have an extremely large set.

So, the solution is GCD and batched fetching. Given that we can assume that only one import is happening at any one time. So once we have performed the initial fetch of all the existing objects, we can split the comparison operations for each of the new objects on to a concurrent GCD queue. We also need a place to store the objects that need to be created, rather than copying them into another collection, we can keep the current collection and gather the indexes of all the new objects, and then create a subset of the superset.

//Compare new hashes against all the known hashes on multiple threads
dispatch_apply([newObjects count], concurrentQueue, ^(size_t idx) {

   //Note that everything that happens here is on a concurrent queue
   if (![hashes member:[[newObjects objectAtIndex:idx] valueForKeyPath:aKeypath]]) {

   //We have synchronize access to the mutable indexset

    [lock lock]; //Lock the index set

    [uniqueIndexes addIndex:idx]; //add the unique index

    [lock unlock]; //Unlock the index set

  }

});


In this case I'm using dispatch_apply (which I personally think is awesome). It will spawn multiple instances of the block on a concurrent queue. Because of the concurrent nature of this method it's important that we lock the NSMutableIndexSet to ensure that it doesn't blow up when two indexes are added at the same time. The current implementation with a simple NSLock results in poor performance on the initial import as every single block will attempt to get the lock so they can add an index. One possible solution is to use a serial dispatch queue to handle the adding of the indexes, and call it via a dispatch_async.

The next part is to split the work of fetching the objects in to smaller batches so we can not only perform smaller units of work, but also have a lower high memory watermark. NSFetchRequest has support for batching requests so this is apparently handled transparently to the rest of the code using a special type of NSArray. However I haven't tested this to ensure it behaves as I expect.

I've posted an implementation as a abstract subclass of NSManagedObject on Github, fork away!