Showing posts with label objective-c. Show all posts
Showing posts with label objective-c. Show all posts

Tuesday, November 13, 2012

When Magical Record stops being magical

Some time ago i discovered Magical Record. It offers some fantastic categories to help you setup your Core Data stack with a single line of code. But it's much more than a Core Data boilerplate thingy. It also offers a range of Active Record pattern like shorthand methods. For example you can find all the instances of a particular type of object without having to write your own NSPredicate and NSFetchRequest using MR_findAll.

Somewhat recently they moved to version 2.0, along with lots of others features they added support for Nested object contexts. If you haven't read about nested/ parent-child managed object context your missing out, especially if you've ever tried to use Core Data with multiple threads.

So when did it stop becoming magical?

Usually i use Magical Record to setup my core data stack, and take advantage of its singleton default context, for those times when i'm too lazy to pass it around like a good engineer. I've also been known to dabble a little with it's Active Record implementation.

However with 2.0, the developer(s) have chosen to change the internal structure slightly. A "Root" context is created at the top of the tree, this has a child context that is returned when you call the MR_defaultContext method. The root context controls the writing of data to disk. This means that if you attempt to save the MR_defaultContext your changes are not persisted to disk, but instead pushed up to the root context.

Well that awesome, right ...

Well it is, if it was obvious. Instead I was left no errors, an empty sqlite db, and no data. Personally I really think they should have just made the MR_defaultContext the root context, and allowed users to nest contexts themselves if they wish. In case your interested you can reach the 'Root' context by calling MR_rootSavingContext.

Anyways after digging around the source code, and a little RTFM I discovered that in order to actually persist your data to disk you have to call MR_saveNestedContexts. This method will recursively call up the tree and save each context. Neat, but not obvious, especially when the API convention is to simply call the native save:

So really this post exists to say, if your a fan of Magical Record and your pulling your hair wondering why save: has stopped working the answer is use MR_saveNestedContexts.



Sunday, September 23, 2012

The evolution of lazy initialization

Lazy initialization is tent pole of Objective C. Apple placed a lot of emphasis on using the pattern in the early iPhone days. That was justified especially considering that the original iPhone shipped with 128MB of RAM, compared to the latest iPhone 5 with 1024MB of RAM.

In the beginning


The ARC evolution


The ARC evolution was fairly tame, allowing us to move the ivar into the implementation files. While the original method was great, and served me well until ARC. With no need to dealloc, and the ability to have iVars that aren't declared in the public interfac.

Clang takes it up a notch


With the most recent versions of Clang you no longer have to use the @synthesize & @dynamic keywords when making @property declarations.
This is all well and good, but I don't want to write my own ivars if I don't have to. So I've set about exploring ways that I can do away with having to create my own ivars.

Option 1.

This approach is comprised of three steps
  1. Public readonly property declaration
  2. Private readwrite property (re)declaration in a class extension
  3. Assign our instance to the ivar

The problem with this is that there is still the ability to overwrite the ivar. Granted it's only from within the class, but still not ideal. This could be an advantage as if you decide to move away from the pattern all you need to do is set the ivar via the mutator.

Option 2.

Another alternative, is to take advantage of another clang feature, where we use the @synthesize directive, to generate a backing ivar on request, without having to explicitly declare the ivar, or at least declare it in a conventional way.
Along with being the smallest version, we can specify the format of our private ivars, so if you want to suffix your underscore rather than prefix it, you have that option.

Whats the solution?

Quite frankly, i don't know. I'm leaning towards Option 2 as it doesn't provide an mutator for the ivar, and so there is almost no suggestion that the ivar should be mutated by anything thing other than the lazy accessor. However I'm interested to hear the opinions of others.

Tuesday, April 12, 2011

Animating a series of images with CALayer

So you want a to animate a series of images, flip book style. While it is true you can use UIImageView, everyone knows that is for wimps. Real men (& ladies ;) ) use CALayer (like a boss)...

But how? Well you might have some how got in your head that CALayer's contents property supports a NSArray of CGImages. Well this is not the answer, remember that the contents property takes an 'id'as a argument so it supports virtually everything under the sun and then some. Hell, if you felt like making crazy things happen you could just throw a NSData object in there.

Anyways, the actual solution is to use a CAKeyFrameAnimation, to manage the rotation of your images, control the frame rate, and ultimately the duration.

Well all is said and done it should look at this

Sunday, April 10, 2011

Drawing text with a Gradient

Problem

You want to draw (unicode) text with filled with a gradient.

Solution

Since my middle name is now "Core Graphics", let me help you out. It's actually pretty simple. Create your desired gradient in a your image editor of choice, and save it as a PNG. Import it into your project and then ...

Yep folks thats it. Now if you find that your gradient is slightly out of place, you can use CGContextSetPatternPhase to help. You of course would use this before your drawing statement. The docs say:

The pattern phase is a translation that Quartz applies prior to drawing a pattern in the context. The pattern phase is part of the graphics state of a context, and the default pattern phase is (0,0). Setting the pattern phase has the effect of temporarily changing the pattern matrix of any pattern you draw. For example, setting the context’s pattern phase to (2,3) has the effect of moving the start of pattern cell tiling to the point (2,3) in default user space.

So when all is said and done you get this lovely effect

text drawn with a gradient Best of all this effect works all the back to iOS 2.0!

Monday, July 26, 2010

Application wide Fonts

So you get your nice shiny PSD's from the designer and your ready to tear though the new UI for your fantastic Application. However their is one problem. While the designs look great, the designer has chosen to use non default fonts. 

AFAIK there is no way to change the global default font for your app. So this means that have UILabel, and UITextField, and UITextView instance that you create needs to have it's font configured.

Configure each might take a while but what will take longer is if they decide to change their mind! While i'm relatively young, i've had this happened enough times that i know you should always plan for it.

so ....

This category provides you with some simply methods modelled on the existing UIFont class methods. Now if you couple this category with categories on the other text rendering classes, you have a nice short hand way to quickly render text in the font you want.



So as an example you could create a category on UILabel, and create a class method called labelWithAppSettings. This method would do the following
  1. Allocate and instantiate a UILabel
  2. Set it's font using one of the methods from UIFont+Additions
  3. Return a Autoreleased object
This would allow us to create (Outside of IB) UILabel's across our application with the default settings by calling [UILabel labelWithAppSettings].

Now if you want to use IB (and you should, cause it's awesome, seriously), you either swizzle or use a category to override the awakeFromNib  on the text rendering classes and set font there.

While the above is very cool, i generally dislike using swizzling, or overriding methods via categories in production code. This generally causes your fellow programmers to swear at you while your not there.

Happy Coding



Sunday, March 28, 2010

Mocking Core Location

One of my current project is a location aware iPhone App. It requires the device to "unlock" a location when the user/device is close enough (a couple of hundred meters).

One of the problems with iPhone development is that there is no way to simulate moving around with the device, or to feed it pre made coordinate data.

Anyone that has worked with the iPhone SDK and Core Location knows that CLLocationManager is the primary class that you need to interact with in order to get location updates.

What i wanted to do was to create a Mock Core Location Manager, that would allow me to create a text file full of coordinates, set a update delay, and then call my Core Location delegate methods, so i can manipulate my app as i please.

If your like me you would think that this should be as simple as creating a CLLocationManger category, and overloading some methods, namely startUpdatingLocation/Heading & stopUpdatingLocation/Heading. 

Now this works for most applications, however it doesn't work with the Iphone's native MapKit's MapView. For that we need to use a different callback then the publicly documented method.

There is a little app called Class Dump that generates header files from compiled binaries. Now thanks to the big drive by hackers to develop for jail broken iphones, you can find copies of the headers without having to generate them yourself.

MKMapView uses a class called MKLocationManager as it's CoreLocation Delegate. You notice that it adheres to the CLLocationMangerDelegate as you would suspect, but along with the public callback method 

locationManager:didUpdateToLocation:fromLocation: 

is also has a very similar method called

locationManager:didUpdateToLocation:fromLocation:usingSupportInfo: 

This is the winner. MKLocationManger will not respond to the former, but will respond to the later. I don't yet know what the usingSupportInfo parameter does. But my assumption is that it is a NSDictionary, however in the example i've posted i simply pass it nil.

So time for some code ...



This is fresh out of the oven, i plan to add a timer and exec the sendUpdate method after a set delay and read the locations from a text file. I'll post it up on git hub if i ever get it done


Update 29/03/10
Since writing this post i've put up a working version of the code on GitHub, Fork away

Monday, March 22, 2010

SVG Graphics on the iPhone

A new project came across my desk. The client want to import vector graphics, manipulate them and export vector graphics. No problem i thought.

Well the problem is that there is no native support for SVG graphics. Not one iota! So as a developer you have two choices. Building a JS interface and loading it in a UIWebView or implementing your own SVG parser, and loading the loading the objects as native paths using Core Graphics/ Quartz 2D.

Most smart programmers would go for the former method of course, however if you have complex SVG's you might have a performance problem, as illustrated by this video


Yeah, that performance sucks.



My problem is two fold, my client wants to export the data as a vector. Common sense wil tell you, that importing multiple vectors and then trying to export them again as a vector, in raster/bitmap based container isn't going to work.


So it looks like me and the SVG spec are going to get really cosy. The only blessing here is that SVG's that my client wants to use are fairly simple, so i should need to implement the entire spec.

Sunday, March 21, 2010

Non Global Singletons in Obj-C

Everyone seems to hate singletons. Personally i find them really convenient, but then i'm a lazy programmer. On my latest client app i decided to take a swing at making a hybrid singleton.

Generally speaking, Cocoa coventions (at least in all the documentation i've read), recommendation for sharing object instances across multiple controllers is to make it part of the application delegate. Personally i hate this, as it leads to a congested app delegate full of random iVars. Now it could be argued that if you find yourself in this place your doing it wrong, and in all truth you probably are. But considering that apple themselves suggest placing the CoreData ObjectContext in the app delegate, i think we're in good company.

My solution takes advantage of one of objective-c's many unique features, categories. Categories allow you to add methods to a class without modifing or subclassing. To most non cocoa programmers i just blew your mind, just wait to you find out about Swizzling!

Essentially i define a category on the class that i want to use as a singleton. In my scenario i wanted to have a single CLLocationManager In my entire app. This is because i need to access the devices location on a regular basis, and i want a global accuracy configuration ... and i just wanna try out some stuff :).

Code time


What i have done is simulated the typical method that you would expect to see for a singleton instance, but behind the scenes this method calls a property on the app delegate to get the shared instance variable.

In my eyes the positives to this approach are:
No global variable for the instance.
The Share instance is where you would expect it to me, and if required can be serialized on app exit.
Accessing the instance is as easy as [CLLocationManager sharedInstance] vs [[[[UIApplication sharedApplication] delegate] locationManager]


Lastly, if the internets tell me that this is a wacky idea i can refractor this to classic singleton, without making mass changes to my app. Thoughts and opinions.