<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1786767290789948563</id><updated>2010-03-01T07:26:01.444+01:00</updated><title type='text'>Lhunath</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.lhunath.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default'/><link rel='alternate' type='text/html' href='http://blog.lhunath.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Lhunath</name><uri>http://www.blogger.com/profile/15117202718575279052</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1786767290789948563.post-5366020400440533414</id><published>2009-08-07T23:17:00.002+02:00</published><updated>2010-01-08T15:37:48.540+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='objc'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Clean up your configuration</title><content type='html'>&lt;span style="font-size: x-large;"&gt;What we all want&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When you're writing an application, whatever platform you're writing it for and whatever framework you're writing it in, you're going to want your users to be able to customize some of it. If that isn't the case with you, you likely write cron jobs all day long and you might as well stop reading.&lt;br /&gt;&lt;br /&gt;Those configurations that our users provide us with need to be stored somehow. Users don't like setting their application up each time they want to use it. Different platforms have different ways of approaching this problem; but generally speaking the approaches are very application-specific and terribly verbose in code. Code verbosity sucks. It makes your code complex and opaque. Your code should be simple and transparent.&lt;br /&gt;&lt;br /&gt;So, what we all really want is a simple, short and generic way of gathering, storing and accessing user configuration; preferably in a way that involves strong type safety of the actual data that each configuration property reflects.&lt;br /&gt;&lt;br /&gt;What I present to you today is an Objective C approach of doing just that.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://images.lhunath.com/yukata.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://images.lhunath.com/yukata.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Persistence&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first obstacle that we need to considder is the persistence of our configuration data. Collected user data is no good to us if we can't remember and recall it.&lt;br /&gt;&lt;br /&gt;Apple provides us with a very useful utility here that goes by the name of &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt;. This is basically a utility class that allows you to specify keys for which values must be persisted and by which we can later recall them again. The &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; takes care of persisting and loading these key and value pairs for us, so we needn't worry about any of that. As a matter of fact; the most we'll ever need to considder the actual persistence of our data is when we're setting an important value that we want to flush straight away (such that it's not reset to the old value should our application crash before &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; decides it's time to flush its cache). In that particular case, we need to invoke &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;synchronize&lt;/span&gt; on our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; object:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;[self.defaults synchronize];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;One caveat: Since we're dealing with persisting data here, we need to make sure that the data we store is actually persistable. In this particular case, that means it should be an instance of: &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSData&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSString&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSNumber&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSDate&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSArray&lt;/span&gt;, or &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSDictionary&lt;/span&gt;. In the case of collections, they may only contain elements that are instances of the same list of classes. Should you like to persist any other data; you'll need to archive it into an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSData&lt;/span&gt; object and unarchive it on access.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;What about initial default values?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While persisting new configuration data is great and all, we still need to actually have default settings for most of our configuration properties before the user has touched them. These can't come from our persistence object because we've never persisted anything with it before; or can they?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt;, our weapon of choice regarding the storage and accessing of our configuration data, comes to the rescue. It provides a means of specifying default values for each of our configuration properties. The default value is returned by &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; whenever we try to look something up that doesn't already have a user-persisted value.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:&lt;br /&gt;                                     [NSNumber numberWithInt: 24],       dFontSize,&lt;br /&gt;                                     ...,&lt;br /&gt;                                     nil]];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Accessing and modifying our settings&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Great! We can store settings and recall them again later. Now if only we could actually access them from our application, that'd be awesome.&lt;br /&gt;&lt;br /&gt;Let me ask you, what is the way for objects to provide other object access to their data? I'm sure you'll all agree with me that the answer to that is simply: &lt;b&gt;Properties&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;So that's what we'll use. Properties in Objective C are type-safe, they are short to declare and easy to access. We even get the choice between the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;[&lt;/span&gt;square bracket&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;]&lt;/span&gt; and the dot&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;.&lt;/span&gt;notation:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@property (readwrite, retain) NSNumber          *fontSize;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's it. Your application now knows how to access the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;fontSize&lt;/span&gt; configuration setting. It can look it up, and it can change it. What's more is that all this is nice and type-safe. Remember to always use the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;retain&lt;/span&gt; attribute on these properties. As a matter of fact; remember to use &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;retain&lt;/span&gt;&amp;nbsp;(or &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;copy&lt;/span&gt;) on all your object properties unless you have a very specific and educated reason not to.&lt;br /&gt;&lt;br /&gt;Now, while our application knows how to get to your settings; your configuration implementation doesn't yet know how to link up our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; with these properties. This step is a little bit more complex than what we've done so far.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Simply put&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In essence, what we need to accomplish is invoking &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-setObject:forKey:&lt;/span&gt; on our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; instance with the key being the name of our configuration property and the value being whatever the user instructed us to store for that setting.&lt;br /&gt;&lt;br /&gt;We could do it quite simply by implementing the setter for the property like thus:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;- (void)setFontSize:(NSNumber *)fontSize {&lt;br /&gt;        &lt;br /&gt;        [self.defaults setObject:fontSize forKey:dFontSize];&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Our setter takes the value given to us by the application and stores it into our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt;. All done. Accessing the setting is as easy as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;- (NSNumber *)fontSize {&lt;br /&gt;        &lt;br /&gt;        return [self.defaults objectForKey:dFontSize];&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The problem this introduces, however, is massive code verbosity. And as agreed earlier; code verbosity leads to opaqueness and is bad. Moreover, the amount of copy-pasting that would be required when implementing a host of configuration properties should give any decent software architect a splitting headache.&lt;br /&gt;&lt;br /&gt;Each of these configuration property implementations will look almost identical. All they need to do is invoke either &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-setObject:forKey:&lt;/span&gt; or &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-objectForKey:&lt;/span&gt; on our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; instance. We should be able to extract all that duplicate code into one single method, right?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Clean that up&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Of course right! This is Objective C; all is possible at runtime! The solution here is to introduce the concept of &lt;b&gt;Message Forwarding&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;The idea is to watch as our application invokes our property and intercept that invocation.&lt;br /&gt;&lt;br /&gt;Instead of providing an implementation of our properties, we'll stop Objective C from trying to find such implementation and instead forward it to a single method that does all.&lt;br /&gt;&lt;br /&gt;Forwarding relies on two things:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Objective C needs to be able to create an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSInvocation&lt;/span&gt; object for your property's getter or setter.&lt;/li&gt;&lt;li&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;We need to intercept each call to our properties with missing implementation and handle them manually.&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;Let's start with the first. Normally, an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSInvocation&lt;/span&gt; object is created by the Objective C runtime whenever a method is invoked by looking up the method signature for that method's selector on your object in your object's implementation. Our problem is that we don't have and implementation and therefore there is nothing for Objective C to generate a method signature from. We'll have to do this manually.&lt;br /&gt;&lt;br /&gt;Since our methods are simple property getters and setters, they aren't all that complex to generate a method signature for. The signature comes from the way Objective C works internally. Any Objective C method call really just dereferences a C function pointer with a return value, the first argument being &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;self&lt;/span&gt; and the second argument being &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;_cmd&lt;/span&gt; which is the selector of the method that is being called.&lt;br /&gt;&lt;br /&gt;Getters have a method signature that says: Return &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;id&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;self&lt;/span&gt; is an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;id&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;_cmd&lt;/span&gt; is a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SEL&lt;/span&gt;. That translates into an Objective C type array of: "&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;@@:&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Setters have a method signature that says: Return &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;void&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;self&lt;/span&gt; is an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;id&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;_cmd&lt;/span&gt; is a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;SEL&lt;/span&gt; and the first argument of my method is an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;id&lt;/span&gt;. This translates into an Objective C type array of: "&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;v@:@&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Here's how we now generate the required method signatures from that information:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {&lt;br /&gt;        &lt;br /&gt;        if ([NSStringFromSelector(aSelector) hasPrefix:@"set"])&lt;br /&gt;            return [NSMethodSignature signatureWithObjCTypes:"v@:@"];&lt;br /&gt;        &lt;br /&gt;        return [NSMethodSignature signatureWithObjCTypes:"@@:"];&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's done. On to number two: Intercepting the call to our missing property implementation.&lt;br /&gt;&lt;br /&gt;Whenever Objective C is asked to perform an invocation on a selector that is not defined in the object instance you're calling it on, the runtime invokes the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-forwardInvocation:&lt;/span&gt; method of that object instance to give it a chance to forward the invocation elsewhere. The default implementation of this method simply just calls &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-doesNotRecognizeSelector:&lt;/span&gt; which raises an exception. This is what causes our applications to terminate when we invoke selectors on objects that do not support them.&lt;br /&gt;&lt;br /&gt;We're going to override this default behaviour and implement our own.&lt;br /&gt;&lt;br /&gt;The goal is simple: Either set the object the application is calling our setter with in the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; or retrieve it for the getter the application is calling.&lt;br /&gt;&lt;br /&gt;The only thing we still need to know before we can write the whole implementation for this is the name of the key in our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt; that we should use to store our property's data. This key name should be something we can easily generate from the data we have when we're in that property's setter or getter. I decided to use the string representation of the property's getter. This gives me two nice perks:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's easy to generate while we're inside our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-forwardInvocation:&lt;/span&gt; call.&lt;/li&gt;&lt;li&gt;It provides an additional level of type-safety.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Type safety? How? Here's how: Whenever you need to reference the key name of a property outside of the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-forwardInvocation:&lt;/span&gt; call (for instance, when setting defaults for that property!), use &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSStringFromSelector(@selector(myProperty))&lt;/span&gt; as the key for &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;NSUserDefaults&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Now, provided you have &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-Wundeclared-selector&lt;/span&gt; set in your build settings' &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;WARNING_CFLAGS&lt;/span&gt; (also called &lt;i&gt;Other Warning Flags&lt;/i&gt;), you'll get the compiler complaining whenever you reference non-existing settings or miss-spell them. Great for knowing what to else to delete or change when you're removing or renaming a configuration property!&lt;br /&gt;&lt;br /&gt;That aside, we now know what our key will be. So, let's get started with our forwarding implementation; and wrap this up!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;- (void)forwardInvocation:(NSInvocation *)anInvocation {&lt;br /&gt;        &lt;br /&gt;        NSString *selector = NSStringFromSelector(anInvocation.selector);&lt;br /&gt;        if ([selector hasPrefix:@"set"]) {&lt;br /&gt;            NSRange firstChar, rest;&lt;br /&gt;            firstChar.location  = 3;&lt;br /&gt;            firstChar.length    = 1;&lt;br /&gt;            rest.location       = 4;&lt;br /&gt;            rest.length         = selector.length - 5;&lt;br /&gt;            &lt;br /&gt;            selector = [NSString stringWithFormat:@"%@%@",&lt;br /&gt;                        [[selector substringWithRange:firstChar] lowercaseString],&lt;br /&gt;                        [selector substringWithRange:rest]];&lt;br /&gt;            &lt;br /&gt;            id value;&lt;br /&gt;            [anInvocation getArgument:&amp;amp;value atIndex:2];&lt;br /&gt;            &lt;br /&gt;            [defaults setObject:value forKey:selector];&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        else {&lt;br /&gt;            id value = [defaults objectForKey:selector];&lt;br /&gt;            [anInvocation setReturnValue:&amp;amp;value];&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It's really simple for when we're forwarding a getter. We just use the string representation of the invocation's selector and we have our key. For the setter we need to trim off the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;set&lt;/span&gt; prefix and lowercase the next character. That gives us the correct string representation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Putting it all together&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, what we have now, is a single class that provides easy access to configuration properties and a dead-easy, type-safe way of adding new properties or refactoring (renaming/deleting) old properties.&lt;br /&gt;&lt;br /&gt;Here's what this all looks like put together. Our tiny interface that defines all our configuration properties in beautiful simplicity:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@interface Config : NSObject {&lt;br /&gt;    &lt;br /&gt;        NSUserDefaults                              *defaults;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @property (readwrite, retain) NSNumber          *fontSize;&lt;br /&gt;    ...&lt;br /&gt;    &lt;br /&gt;    + (Config *)get;&lt;br /&gt;    &lt;br /&gt;    @end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Our slightly more complex but safe and (relatively) short implementation:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#define dFontSize                               NSStringFromSelector(@selector(fontSize))&lt;br /&gt;    &lt;br /&gt;    @interface Config ()&lt;br /&gt;    &lt;br /&gt;    @property (readwrite, retain) NSUserDefaults    *defaults;&lt;br /&gt;    &lt;br /&gt;    @end&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;    @implementation Config&lt;br /&gt;    &lt;br /&gt;    @synthesize defaults;&lt;br /&gt;    @dynamic fontSize, ...;&lt;br /&gt;    &lt;br /&gt;    - (id)init {&lt;br /&gt;        &lt;br /&gt;        if (!(self = [super init]))&lt;br /&gt;            return nil;&lt;br /&gt;        &lt;br /&gt;        self.defaults = [NSUserDefaults standardUserDefaults];&lt;br /&gt;        [self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:&lt;br /&gt;                                         [NSNumber numberWithInt: 24],       dFontSize,&lt;br /&gt;                                         ...,&lt;br /&gt;                                         nil]];&lt;br /&gt;        &lt;br /&gt;        return self;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    - (void)dealloc {&lt;br /&gt;        &lt;br /&gt;        self.defaults = nil;&lt;br /&gt;        &lt;br /&gt;        [super dealloc];&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    + (Config *)get {&lt;br /&gt;        &lt;br /&gt;        static Config *configInstance;&lt;br /&gt;        if(!configInstance)&lt;br /&gt;            configInstance = [[Config alloc] init];&lt;br /&gt;        &lt;br /&gt;        return configInstance;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {&lt;br /&gt;        &lt;br /&gt;        if ([NSStringFromSelector(aSelector) hasPrefix:@"set"])&lt;br /&gt;            return [NSMethodSignature signatureWithObjCTypes:"v@:@"];&lt;br /&gt;        &lt;br /&gt;        return [NSMethodSignature signatureWithObjCTypes:"@@:"];&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    - (void)forwardInvocation:(NSInvocation *)anInvocation {&lt;br /&gt;        &lt;br /&gt;        NSString *selector = NSStringFromSelector(anInvocation.selector);&lt;br /&gt;        if ([selector hasPrefix:@"set"]) {&lt;br /&gt;            NSRange firstChar, rest;&lt;br /&gt;            firstChar.location  = 3;&lt;br /&gt;            firstChar.length    = 1;&lt;br /&gt;            rest.location       = 4;&lt;br /&gt;            rest.length         = selector.length - 5;&lt;br /&gt;            &lt;br /&gt;            selector = [NSString stringWithFormat:@"%@%@",&lt;br /&gt;                        [[selector substringWithRange:firstChar] lowercaseString],&lt;br /&gt;                        [selector substringWithRange:rest]];&lt;br /&gt;            &lt;br /&gt;            id value;&lt;br /&gt;            [anInvocation getArgument:&amp;amp;value atIndex:2];&lt;br /&gt;            &lt;br /&gt;            [self.defaults setObject:value forKey:selector];&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        else {&lt;br /&gt;            id value = [self.defaults objectForKey:selector];&lt;br /&gt;            [anInvocation setReturnValue:&amp;amp;value];&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1786767290789948563-5366020400440533414?l=blog.lhunath.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.lhunath.com/feeds/5366020400440533414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1786767290789948563&amp;postID=5366020400440533414' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/5366020400440533414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/5366020400440533414'/><link rel='alternate' type='text/html' href='http://blog.lhunath.com/2010/01/clean-up-your-configuration.html' title='Clean up your configuration'/><author><name>Lhunath</name><uri>http://www.blogger.com/profile/15117202718575279052</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04614975865096498678'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1786767290789948563.post-8586233151682217644</id><published>2009-05-03T09:44:00.002+02:00</published><updated>2010-01-08T15:32:50.553+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>Application sales statistics from the CLI</title><content type='html'>&lt;span style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;span style="font-size: 11px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;span style="font-size: 11px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;span style="font-size: 11px;"&gt;&lt;div&gt;&lt;span style="font-size: x-large;"&gt;The problem&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Apple provides us, developers, with sales data which nicely details which of our applications have sold when and to whom. This data comes in the form of gzipped plain text files that use a CSV-like format (in fact, tab-delimited) of encoding data fields.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's not exactly very human-readable. And while Apple provides a quick and simple "preview" button for these reports, it's hardly useful either. What we'd like to see is some statistics on how many applications we've sold in total, to whom, in what currencies, what countries and most importantly, how much profit it's made us!&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sadly, Apple does not provide, but they do give us what we need to roll our own solution. And many have. There are applications all around that parse these reports Apple gives us and render them in graphs or dump them in tables. Unfortunately, almost all of these are made by developers that like to charge. I haven't come across anything noteworthy that's freeware.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: x-large;"&gt;The solution&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How would I solve this problem? Easy enough, I'm a developer; I might as well roll up my sleeves and get started myself. And I did.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I decided that what I wanted was something simple and fast. I didn't need the charts, all I wanted was to know how much I'd sold since the last time I checked and what my profit meter looked like so far. I'm a CLI-guy, so I wanted a way of running something from the CLI and immediately getting all the feedback I'm interested in.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: x-large;"&gt;Enter: iphone-stats&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I opened my &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;vim&lt;/span&gt; and got to it. The result is a series of bash scripts that do everything I'm interested in for the moment. They parse my sales data (which is daily sales reports nicely organized in subdirectories named after their month) and write out some statistics on my terminal. Moreover, scripts are also provided that fetch iTunes App Store reviews on my applications and fetch my daily iTunes Connect reports for me through a cron job.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's what the first script, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;stats&lt;/span&gt;, looks like:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.lhunath.com/iphone-stats/stats.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="207" src="http://www.lhunath.com/iphone-stats/stats.png" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A second script, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;reviews&lt;/span&gt;, downloads customer reviews from the iTunes App Stores world-wide. This is a great way of keeping track what people are saying about your applications.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's what that looks like:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.lhunath.com/iphone-stats/reviews.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="207" src="http://www.lhunath.com/iphone-stats/reviews.png" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A third script, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;fetchdailies&lt;/span&gt; is a script that checks which the last daily report that you have is and downloads any available dailies past that. You can run it quickly from the CLI, like the other scripts, and it'll tell you what it's doing, or you can schedule it in a cron job so that it'll automatically download your available dailies for you every day.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The last script uses a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;python&lt;/span&gt; script called &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;appdailysales&lt;/span&gt;, which is not mine, but is an open-source script written mostly by Kirby Turner. I've adapted it for security (of passing the password) and integration (with iphone-stats). You can, of course, invoke it directly. It has good help output if you start it with the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;-h&lt;/span&gt; argument:&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.lhunath.com/iphone-stats/appdailysales.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="207" src="http://www.lhunath.com/iphone-stats/appdailysales.png" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-size: x-large;"&gt;Availability&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The whole bundle of scripts is available from the (quick and dirty) &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;iphone-stats&lt;/span&gt; homepage at:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.lhunath.com/iphone-stats"&gt;http://www.lhunath.com/iphone-stats&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I recommend you go through the &lt;a href="http://www.lhunath.com/iphone-stats/README"&gt;README&lt;/a&gt; file contained within: It details the use very well and in great detail. Of course, you can also &lt;a href="mailto:lhunath@gmail.com"&gt;contact me&lt;/a&gt; directly if you have any issues.&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1786767290789948563-8586233151682217644?l=blog.lhunath.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.lhunath.com/feeds/8586233151682217644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1786767290789948563&amp;postID=8586233151682217644' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/8586233151682217644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/8586233151682217644'/><link rel='alternate' type='text/html' href='http://blog.lhunath.com/2009/05/application-sales-statistics-from-cli.html' title='Application sales statistics from the CLI'/><author><name>Lhunath</name><uri>http://www.blogger.com/profile/15117202718575279052</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04614975865096498678'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1786767290789948563.post-2386455295983496375</id><published>2009-04-19T17:30:00.003+02:00</published><updated>2010-01-08T15:35:02.212+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='objc'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>The memory management battle that wins the war.</title><content type='html'>&lt;span style="font-size: x-large;"&gt;From Java to (Objective) C&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I used to be a Java guy. Java, the language of type safety, UIs that stick out like a sore thumb, and a VM that sucks your RAM dry; yes, I was all for it. I loved the simplicity with which you express relationships, the trust you have that compilable code (if written sanely) is safe, the beauty of IoC and unit testing, you name it.&lt;br /&gt;&lt;br /&gt;Understandably, I was struck with horror and panic when I realized that my new ambition, iPhone development, would require me stepping away from all that. I soon learned that Objective C, while a beautiful and respectable language in its own league, is nowhere as safe as Java. Everything you do in it is dangerous: Half of the problems are only detectable at run-time, refactoring in and indexing it is a nightmare (mostly because of its inheritly dynamic nature) and there's really no decent IDE for it.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://images.lhunath.com/poolboat.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://images.lhunath.com/poolboat.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Trade-offs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At the same time, all this playing with fire also adds some compelling new ways of getting things done. Where Java has reflection, Objective C goes so much further in a far cleaner way.&lt;br /&gt;&lt;br /&gt;To those that have already dipped their fingers in the Java reflection sauce it's clear what an absolute mess your code soon becomes. The beauty of simplicity that Java can be becomes a horrid web of loosely-coupled constructs that affect each other in most unpredictable ways. Reflection is the name of the Java-antichrist, here to tempts us into ruining everything good and pure about writing in the Java language.&lt;br /&gt;&lt;br /&gt;Objective C, being a very flexible language by its very nature, provides a bunch of interesting similar features. Admittedly, though, it does it with style. Categories, dynamic properties, pointers, you name it. They're all very nicely integrated into the language and don't bloat or worsen the type-safety of the code too much. Granted, you don't start off from the same level of type safety either.&lt;br /&gt;&lt;br /&gt;All this flexibility comes at a very important price, though. Very little about the code is certain at compile-time. While you can convince the compiler to warn you of most bad practices and eliminate a large part of possible bugs that the Java compiler wouldn't even agree to compile, and while sticking to sane code practices goes a long way, you are never certain that your code won't cause illegal pointer dereferencing, method calls on objects that don't even have those methods or allow buffer overflows. These are things that are almost impossible in Java (provided you aren't tinkering with reflection - and even then there's an impecible exceptions framework with checked exceptions that has your back).&lt;br /&gt;&lt;br /&gt;The baddest of the bunch, the nastiest of nasties, the meanest of the meanies, is, still memory (pointer) management. While there are very good rules about what you should and shouldn't be doing, I want to be able to trust that the code I have runs perfectly. I don't want to be called by QA or see customers complain: I want my compiler to complain before anyone else sees the stupid mistake I made late last night.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Enter: Properties&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Objective C 2.0 has some very interesting features that help with memory management. Sadly, some are not available in the work I'm doing. Since I'm an iPhone developer, I cannot benefit from the garbage collection, for instance. That is a feature privileged for those blessed Mac developers.&lt;br /&gt;&lt;br /&gt;Something that is available to iPhone developers: properties. Properties are the what I have dreamt of since the first week I set foot on Java soil. They are a type-safe, simple and clean way of defining and declaring instance variable accessors and setters. Many languages have a variant of these, sometimes with the same or a different name, except for Java. In Java you're still forced to explicitly declare getters and setters for each and every instance variable that you want to reveal to the outside world in a safe and encapsulated object-oriented type of way.&lt;br /&gt;&lt;br /&gt;Not only are they beautifully simple, they also pack a punch: Properly used property declarations are the answer to all your memory management woes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;How properties will save your life&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The beauty of properties lies in the fact that the compiler uses them to generate getters and setters that do all the important work for you. The code that is generated depends on the hints you specify in the property definition: The property attributes. These attributes make sure that access to the instance variable that backs the property is done in a insistent and safe way.&lt;br /&gt;&lt;br /&gt;We can declare the following attributes on our properties:&lt;br /&gt;&lt;br /&gt;readonly/readwrite: Specify whether we need just a getter or also a setter.&lt;br /&gt;nonatomic: Specify whether we need access to the property to be atomic (synchronous) or not.&lt;br /&gt;retain/copy/assign: Specify whether the type of memory management we need to perform on the property.&lt;br /&gt;The way most people use properties is quite straight forward. They declare an instance variable in their class header, add a property to it with the same name and type, specify appropriate attributes and synthesize them in the respective class implementation block.&lt;br /&gt;&lt;br /&gt;The beauty of properties is that they provide a central and trustworthy way of declaring how our instance variables must be used. For instance, specifying retain on our property means that every time we assign a value to the property the generated setter will release any existing object assigned to the instance variable and retain the new object before assigning it to the instance variable.&lt;br /&gt;&lt;br /&gt;While the use of well-defined properties results in perfectly safe code, problems can still occur when we go behind the property's back. There are two things we can do to mess things up:&lt;br /&gt;&lt;br /&gt;Accessing the instance variable directly.&lt;br /&gt;Invoking retain, release, autorelease or, God forbid, dealloc on the object in our property ourselves.&lt;br /&gt;I said "well-defined" because, understandably, using incorrect attributes on our properties will also mess things up. The best example of badly defined properties is NSObject-typed properties with the assign attribute. Objects should always have the retain or copy attribute. Objects with the assign attribute are weak links. That means that our property does not take part in the memory management of the object. As a result, whenever the party that does take part in the memory management of the object decides it's done with it and causes it to get deallocated, our property might still reference the object. The results are predictable: application crash imanent.&lt;br /&gt;&lt;br /&gt;Knowing that, the answer to all our worries is: "Hands off of property managed memory!". In practice, this means avoiding the above two at all costs.&lt;br /&gt;&lt;br /&gt;You should never access instance variables directly: Use the property provided accessor methods for that. They provide an encapsulated and safe way of accessing our instance variables. There should never be a reason to access the instance variable directly.&lt;br /&gt;&lt;br /&gt;You should also never send memory management messages to any objects managed by properties. Properties rely on the managed objects' retain state to be as they set it. Whenever you send messages directly to the managed objects you will break that reliance, and with it, your code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;Asserting the rules&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While it's great to know good coding practices, knowing them doesn't assert that our code is safe. It's easy to slip up, especially so when multiple developers work on the same codebase. For this reason, it's important to put into effect code practices that help us make sure we abide by the rules, and help us detect whenever we don't or prevent us from breaking them.&lt;br /&gt;&lt;br /&gt;As mentioned before, there are three important things we need to keep in mind: avoiding direct ivar access, avoiding manual memory management and using the correct property attributes. The last two are really a matter of keeping your head when coding: we can't do much to enforce this at compile-time.&lt;br /&gt;&lt;br /&gt;To aid us stick to the first, though, I recommend the following code style. It encourages object encapsulation and discourages, but more importantly, makes direct instance variable access very noticable.&lt;br /&gt;&lt;br /&gt;We begin with our interface declaration:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Foo.h:&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;@interface Foo : NSObject {&lt;br /&gt;        @private&lt;br /&gt;        NSString                                *_name;&lt;br /&gt;        NSArray                                 *_friends;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @property (readonly, copy)      NSString    *name;&lt;br /&gt;    @property (readonly, retain)    NSArray     *friends;&lt;br /&gt;    &lt;br /&gt;    -(id) initWithName:(NSString *) name&lt;br /&gt;            andFriends:(NSArray *)  friends;&lt;br /&gt;    &lt;br /&gt;    @end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Things to note here are the underscore-prefixed instance variables and the copy/retain attributes on readonly property definitions. We use underscore-prefixed instance variables because the only place where we want to reference our instance variables is when we synthesize our properties. Underscore-prefixing them makes it very unlikely we'll ever accidentally reference them from implementation code and means whenever we do, it stands out like a sore thumb in our code. The copy and retain on readonly properties is to avoid a compiler warning which will be caused by our later redefinition of those properties:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Foo.m:&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;@interface Foo ()&lt;br /&gt;    &lt;br /&gt;    @property (readwrite, copy)     NSString    *name;&lt;br /&gt;    @property (readwrite, retain)   NSArray     *friends;&lt;br /&gt;    &lt;br /&gt;    @end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is a class extension which we put in our implementation file. It overrides the property definitions from earlier making them readwrite instead of readonly. However, the setter will only be visible to the implementation, not to anyone using our class. Considder it a private setter. If you need your setter to be public, however, there's no need for this and you should just make it readwrite in the header file. Now, on to our implementation:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Foo.m:&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;@implementation Foo&lt;br /&gt;    &lt;br /&gt;    @synthesize name    = _name;&lt;br /&gt;    @synthesize friends = _friends;&lt;br /&gt;    &lt;br /&gt;    -(id) initWithName:(NSString *) name&lt;br /&gt;            andFriends:(NSArray *)  friends {&lt;br /&gt;    &lt;br /&gt;        if(!(self = [super init]))&lt;br /&gt;            return nil;&lt;br /&gt;    &lt;br /&gt;        self.name       = name;&lt;br /&gt;        self.friends    = friends;&lt;br /&gt;    &lt;br /&gt;        return self;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    -(void) dealloc {&lt;br /&gt;    &lt;br /&gt;        self.name       = nil;&lt;br /&gt;        self.friends    = nil;&lt;br /&gt;    &lt;br /&gt;        [super dealloc];&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;&lt;span style="font-style: normal;"&gt;Notice how in the we need to specify the name of the instance variables that will back our properties in their synthesize declarations. That's because the property name is not the same as the instance variable name. It's also the only place in your code you should reference your instance variables. Beyond that, you'll be using the properties whenever you need to access or set the instance variable's data. Even in the dealloc method you'll be using only just your properties. Setting them to nil will cause the object held by the respective instance variable to get released if the property is set to retain or copy. This means no explicit memory management and centralized memory management configuration per property.&lt;/span&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1786767290789948563-2386455295983496375?l=blog.lhunath.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.lhunath.com/feeds/2386455295983496375/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1786767290789948563&amp;postID=2386455295983496375' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/2386455295983496375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/2386455295983496375'/><link rel='alternate' type='text/html' href='http://blog.lhunath.com/2009/04/memory-management-battle-that-wins-war.html' title='The memory management battle that wins the war.'/><author><name>Lhunath</name><uri>http://www.blogger.com/profile/15117202718575279052</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04614975865096498678'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1786767290789948563.post-641644691022281884</id><published>2009-04-18T21:35:00.003+02:00</published><updated>2010-01-08T15:36:16.814+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='something new'/><title type='text'>A brave attempt at something new.</title><content type='html'>&lt;span style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;span style="font-size: 11px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-family: inherit;"&gt;Yet another weblog&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family: inherit;"&gt; &lt;br /&gt;Rambling. It's a favorite past-time of anyone self-respecting. We see the people around us doing stupid things and feel the irresistable need to ramble about it. Even though we all make mistakes, and we all do stupid things, it somehow makes us feel better pointing out just how badly some people got it wrong.&lt;br /&gt;&lt;br /&gt;The unstoppable evolution of the new web has blessed all us ramblers with a giant gateway to broadcast our ramblings to the rest of the world. Oddly enough, it appears this practice has in fact become truly popular. Web logs pop up all over the place with countless providers trying to pull in anyone with enough time to perform a brain-dump every so often. The practice has even turned profitable. Why? It appears that not only is it in our very human nature to have an opinion on everything and a desire to share it with everyone, it is also truly addictive to follow fellow ramblers and keep up on the latest gossip.&lt;br /&gt;&lt;br /&gt;RSS feeds are more popular than ever before and millions of hours of work are wasted every single day by people reading others' web logs instead of doing what they're payed to do. Alas, such is the recent turn of events, and for better or for worse, it's a perfectly natural evolution of our very nature.&lt;br /&gt;&lt;/span&gt;   &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://images.lhunath.com/poolleaf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span style="font-family: inherit;"&gt;&lt;img border="0" src="http://images.lhunath.com/poolleaf.png" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;   &lt;span style="font-size: x-large;"&gt;&lt;span style="font-family: inherit;"&gt;Really no different than the rest of them&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;br /&gt;Contradictory to what the above introduction might elude to, I'm really no different than the rest of them. I have my opinions, and more often than not, they're hardly as educated as I might pretend.&lt;br /&gt;&lt;br /&gt;Therefore, I've decided it's time I join the ranks and open up a web log for anyone with unwasted time left to read and follow.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span style="font-family: inherit;"&gt;Subject&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;br /&gt;The main subjects you'll find lurking in the entries here will be those I'm generally most vocal about:&lt;br /&gt;&lt;/span&gt;  &lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;Bash Shell Scripting&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;Java Design and Development&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;iPhone Development and Objective C&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1786767290789948563-641644691022281884?l=blog.lhunath.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.lhunath.com/feeds/641644691022281884/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1786767290789948563&amp;postID=641644691022281884' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/641644691022281884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1786767290789948563/posts/default/641644691022281884'/><link rel='alternate' type='text/html' href='http://blog.lhunath.com/2009/04/yet-another-weblog-rambling.html' title='A brave attempt at something new.'/><author><name>Lhunath</name><uri>http://www.blogger.com/profile/15117202718575279052</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04614975865096498678'/></author><thr:total>0</thr:total></entry></feed>