Creating a category on NSUserDefaults is a pretty common activity, I believe I first saw the technique in iOS Recipes and I've done it ever since. By writing a category you can make your use of NSUserDefaults follow how you write code everywhere else using accessors and having the compiler check this for you without messing with string keys.
As a result the standard usage of NSUserDefaults may look something like this
Defaults without properties
The issue here is that there is a lot of noise in the above code which hides what we are doing - simple assignment and retrieval.
By adding a category we can simplify this
We can now rewrite the first example using this category, which has the nice effect or removing most of the noise and making our intent clearer.
Defaults with properties
This technique is nice but as you can see it requires a fair amount of boiler plate code and all of this was to just add one property.
When reading an issue of iOSDevWeekly I saw the class GVUserDefaults mentioned and this got me intrigued. The class uses some Objective-C mataprogramming to lazily add getters and setters at runtime. It's worth checking out but it does have some limitations, which got me to thinking how would I do this?
I ended up going a different route and making a Ruby gem that uses a simple DSL to generate the category and add it to your Xcodeproj. It's just a different approach to the same problem.
The best place to read about how to try my gem out is on the project page here.
You can't use your system version of Ruby (as it is too old) but rvm or rbenv are pretty easy to set up and then it's as simple as
gem install defgen
Features of Defgen
Uses the class prefix of your project to prefix all the things
Uses the organization name of your project in generated class comments
Uses a simple DSL and supports all the types that NSUserDefaults does
You can supply custom getter semantics
You can edit all of the templates used for code generation on a project by project basis to conform to your coding style
The process of making this gem was fun but a pretty steep learning curve for me, hopefully if this proves useful I have some other ideas for other things that could do with code generating DSL's.
Blocks are a lot of fun and they can make some really slick API's. It's also worth noting that blocks also require a fair amount of overhead to get used to how they work and how to use them. I would consider myself fairly competent with blocks but this confidence can lead to potentially "clever code". "Clever code" is sometimes hard to maintain depending on how clever you was feeling at the time of writing it.
In this post I intend to cover one such bit of "clever code" and how it could be implemented differently to compare and contrast the results.
I'll start by looking at the implementation I didn't actually do and then step by step arrive at the solution I initially wrote. From here I can compare and contrast and see which solution I should have done.
The sequence of events looks something like this
So at this point we have a working solution and all is good.
The code to loop over the points looks something like this
Something about asking for the count and then iterating over it seems a little awkward to me, I'd much rather the thing that held this information (the model) kept it's data a little closer to it's chest and iterated over itself passing out the points. There are two options here
Add some kind of enumerator
I prefer the second option
The block enumeration ends up looking like this:
This creates an issue - for this to work I would have to call this enumerator in the View. I could simply bypass the Controller and pass the View a reference to the Model but I don't like the sound of this. The more pressing issue is that the Model works in a different coordinate space to the View and the Controller is currently handling this conversion.
To get this to work I'll need to restructure to look like this
This diagram actually looks simpler. There's a couple of things to now note
There are new required methods that need to be called and in a specific order beginDrawing and commitDrawing
The path building now occurs over a series of method calls to View
Straight away I can see a way to remove the requirement to call beginDrawing and commitDrawing at this level by using a block that wraps this up in a tasty sandwich.
The sandwich block puts the interesting code that changes as the sandwich filler and the boilerplate as the bread, which will look like this:
This hides a message in our sequence diagram and removes the requirement to remember to call beginDrawing and commitDrawing.
So actually getting the View to draw can now all be kicked off from the Controller and would look something like this:
Now at this point we can look at the public interfaces of the MVC trio and it's looking quite smart
Every object appears to be toeing the MVC line, although I see a method that probably doesn't belong in the public API. The View now has the method -[View buildWithPoint:], which only makes sense in the context of drawing, it's not clear by looking at the public interface what this method does or in what context to call it.
So here's another opportunity to use a block, this final implementation brings us to the title of this post Blockception. We now end up with a block in a block which calls a block passed in by the first block.
This ends up looking like the following:
The drawBlock essentially takes the functionality of the old -[View buildWithPoint:] and passes it straight where it is actually needed.
The delegate implementation requires a fair amount more code to write. A @protocol needs to be introduced to allow the view to have a dataSource. There is also the methods on the controller that conform to this protocol and end up proxying them straight onto the Model and then slightly changing the result.
Looking at the initial sequence diagram there seems to be more back and forth of messages to achieve the same result than where we end up.
The Model is required to expose how many elements it has and then allow an external object to iterate over that in a way which is out of it's control.
The block implementation has 2 of my favorite ways to use blocks, which are for enumeration and wrapping code.
The public interfaces for all the objects expose very little about themselves, which is always nice.
There are considerably more awkward carets and curly braces, which can be confusing.
Looking back at both solutions the delegate technique can be easier to fully grasp and follow along. The block implementation completely failed my "can I explain how this is working to a colleague in one attempt" rule, but I feel the delegate setup would only fair slightly better.
The reason I originally implemented this using blocks over delegates was purely because I had the block enumeration on the Model and this was the only way I could think to make it all fit.
I do like how the block implementation hides away any gory details about the structures of the objects but the very fact that I've had to write a blog post about this probably means it's too clever. I think the answer to "which is better?" is we'll have to wait and see how the block implementation stands up over time.
A friend finally got Alfred and was excited to see some of the extensions available. I had dismissed a lot of these as just tools I would never use, that was until I saw a couple that got me thinking. The first one is called Open Terminal Here, which opens the terminal to the location of the front most finder window. The second extension is called Using Alfred to clone a github repository.
My general workflow goes something like this
Clone something to my tmp directory*
Get into the directory
Open in some editor
*I have a habit of sticking everything in /tmp otherwise I end up with lots of clutter that I will never find the time to remove
The extension I want is essentially the love child of the two that I have mentioned. This is what I came up with
This is horrible Applescript which I normally try and avoid with a 10ft barge pole but it got the job done.
Line 1 and 9 enable us to get the parameter passed into Alfred which will be a git url.
Line 5 uses ruby to get the gems name so we can create a directory with the correct name and cd into it
Line 6 Uses terminal to get us into the /tmp directory, clones the repo and then gets us into the new directory
It's by no means perfect but it gets the job done allowing me to try things out and automating the steps I normally take.
Doing repetitive work over and over is always frustrating. Thankfully good developers automate the things they do or find other people who have done the hard work already.
You don't have to be amazing at scripting to hack something together that can really make things easier. People often stray away from tech they are not used to but it's worth just "giving things a go" to see how you get on.
Here's a simple Ruby script that I use several times a day when working with my Xcode projects.
I often start from or find myself on the command line using Git or navigating my projects. I also like to use CocoaPods to deal with project dependencies. This results in an annoying issue when opening Xcode, for projects that use CocoaPods you need to open the *.xcworkspace and for projects that don't use CocoaPods you need to open *.xcodeproj. I also do not enjoy using the graphical File->Open....
Make a little script to deal with the inconsistency and allow me to open projects quickly form the command line.
The key to this script is that I don't get bogged down with details of how to implement it perfectly. It does exactly what I need and should be easy to follow at a later date if I need to change anything.
The initial version of this script had a potential floor which was pointed out by my colleague Oliver Atkinson. In the first instance I didn't use shellwords to escape the project name. This causes an issue if the name has a space in it, which had never affected me personally as I always camel case my project names, but it's an edge case that will be hit often when sharing code with others.
The main take away from this learning is that I didn't need to spend hours making the script perfect (and I'm sure it still isn't) as it suited my requirements - as soon as the requirements change it's time to fix it up and make it work.
One of the cool things about RubyMotion is that when you run your app you get a REPL (read, eval, print, loop) that you can quickly try some code out in. Although it's not as easy to use, the debugger in Xcode (I'm using lldb) can give you some of the same experience when it comes to interrogating objects and trying basic things.
Here are some simple examples of techniques to use to help you out:
I can never remember how I'm supposed to spell font names when using +[UIFont fontWithName:size:], so I'll often just set a break point anywhere to get me into the debugger and then ask UIFont:
(lldb) po [UIFont familyNames]
(id) $1 = 0x06a9e450 <__NSCFArray 0x6a9e450>(
Academy Engraved LET,
Oriya Sangam MN,
Bodoni 72 Smallcaps
This is cool but I'm lazy and I want this output sorted so I don't have to scan up and down
(lldb) po [[UIFont familyNames] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
(id) $2 = 0x06aa28f0 <__NSArrayI 0x6aa28f0>(
Academy Engraved LET,
Apple Color Emoji,
Apple SD Gothic Neo,
Now that's much easier to look at.
Just a quick note there are a couple of ways I could have done this. I used [UIFont familyNames] nested inside the sortedArrayUsingSelector: method, but I could have just as easily used
The memory address of the originally returned array [0x06a9e450 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
The variable that the result of the first expression was assigned to [$1 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
Now I'm deeply saddened that Comic sans is not in this list but I can see something that sounds equally as awesome "Chalkboard SE". So to answer my original question and find out what I need to use in my +[UIFont fontWithName:size:] I will again ask UIFont:
You'll find that you actually need to cast a lot so just be very aware of that.
Here's a couple examples of that
(lldb) p [self.view bounds]
error: no known method '-bounds'; cast the message send to the method's return type
error: 1 errors parsing expression
(lldb) p (CGRect)[self.view bounds]
(CGRect) $9 = origin=(x=0, y=0) size=(width=320, height=460)
(lldb) expr (void)[self.view setBackgroundColor:[UIColor redColor]]
error: no known method '+redColor'; cast the message send to the method's return type
error: 1 errors parsing expression
(lldb) expr (void)[self.view setBackgroundColor:(UIColor *)[UIColor redColor]]
(lldb) expr (void)[self.view setBackgroundColor:(id)[UIColor redColor]]
Now I have no idea if this is useful/safe but you can actually mess around fairly freeform
I'll start off by making a command alias to run the runloop
Now I actually have a label on the screen with my text in it, without leaving the debugger.
The examples provided here are fairly contrived, but the take away is that if you get familiar with the debugger you can actually do some cool experimentation. Here I've shown how to do some basic interrogation of objects without adding NSLog()'s and rebuilding, which is pretty cool. I've certainly had occasions where I've had a designer stood over my shoulder to tweak some UI and I would have loved to not have to rebuild repeatedly while we both wait just to check that the pixel adjustments were correct, especially when the view being edited was deep in a navigation stack and required a lot of clicking.