Showing posts with label Cocoa. Show all posts
Showing posts with label Cocoa. Show all posts

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!

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!


Sunday, March 17, 2013

FRCoreDataExportOperation

Core Data is possibly one of the most useful frameworks in iOS. People have different feelings towards it, but i'm a solid fan. One issue that i'm sure everyone has had with core data at one point or another is getting data in and out of Core Data. This ultimately led to creation of the FRCoreDataOperation project.

A few months ago I started using FRCoreDataOperation to serialize Core Data objects to disk. Sure you could do this with plists, but thats a little too restrictive especially if you want the serialized data to be compatible with other applications and platforms. Usually my format of choice is CSV, as you can import it into excel/ google docs easily, also python has a great module for loading CSV data.

For another project I found myself needing to do the same thing again, the classic sign that it was time to do make something reusable and adaptable. So FRCoreDataExportOperation was born. FRCoreDataExportOperation is a concrete subclass of FRCoreDataOperation and can be used without subclassing. Below is an example of how you use the class.

There are a series of initializers that you can use in tandem with the class, but the one you'll probably most interested in is below.

As you can see by using a predicate and sort descriptors along with the entity name you can select the objects you want to export. The export operation also supports relationships, it's not completely recursive, and will only explore entities that have a direct relationship with the entity you specified.

The next step is to select a formatter, the actual serialization format is completely abstracted from the class and is performed by the object assigned to FRCoreDataExportOperation's entityFormatter property. Thus far i've only created the FRCoreDataEntityFormatter, FRCSVEntityFormatter, but you can create your own by implementing the FRCoreDataEntityFormatter protocol.

The FRCSVEntityFormatter is somewhat customizable, and allows you to specify a NSArray with the  keypaths that you want to be serialized to disk. The columns will be written in the order they appear in the array. If you choose to use the formatter without a whitelist, all of the properties will be written in the alphabetical order of the property name.

Best of all you can get this for yourself via Cocoapods, pod is aptly called FRCoreDataOperation

Happy exporting

Wednesday, September 07, 2011

Making UIImages with blocks

So i was going to post about something completely different today, but as i was typing i looked at my code, and thought it was verbose and a little bit ugly.

So i made it awesome, and as everyone knows to make your code awesome you add some blocks to it.

My problem was simple, i was faced with the need to create two CGBitmapContext, for the uniformed the following code is required to prepare a bitmap context for drawing.


So after a bit of thought, i decided what i really wanted was a method that did all of this for me, and meant that i didn't have to worry about constantly checking the code for leaks (DRY), and that was pleasant to look at and i came up with the above. The block that you pass in is given a fully formed CGBitmapContext, and the method returns a UIImage generated from that context. Almost like a UIView/CALayer.



So now your thinking, "Yeah, thats cool, but why the [INSERT FOUR LETTER WORD] would i want to use it ?" Well young grasshopper, have you ever wanted to mask a image in code? You know to do those trendy rounded corners ... well yes you can use CALayer's however the idea of using those off the main thread makes me uneasy, and we all know the cool kids do things in the background.


The above actually creates a rounded rect on the fly, and masks the image with it. It's made to be used in a category on UIImage. But look closer, yep thats right kids, no boiler plate, ZERO, NADA, 另, SQUAT (i think you get the point)!

I should take a moment to mention that the awesome code for the rounded rect comes from the awesome Oliver Drobnik, i have the utmost respect for this guy, not just for this snippet, but if you've ever seen his Rich text label and it's associated projects, you'll understand why real soon.