<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
> <channel><title>Adrian Kosmaczewski &#187; How to?</title> <atom:link href="http://kosmaczewski.net/category/how-to/feed/" rel="self" type="application/rss+xml" /><link>http://kosmaczewski.net</link> <description></description> <lastBuildDate>Mon, 06 Feb 2012 08:40:05 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>HTTP Headers, Web Apps and Mobile Safari</title><link>http://kosmaczewski.net/http-headers-web-apps-and-mobile-safari/</link> <comments>http://kosmaczewski.net/http-headers-web-apps-and-mobile-safari/#comments</comments> <pubDate>Fri, 30 Oct 2009 15:24:06 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[How to?]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[programming]]></category> <category><![CDATA[Safari]]></category> <category><![CDATA[web]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=2047</guid> <description><![CDATA[I found today that Mobile Safari, the browser bundled with the iPhone, has a very strange and annoying behaviour when it comes to web apps. In fact, when you &#8220;install&#8221; web applications with the &#60;meta name=&#34;apple-mobile-web-app-capable&#34; content=&#34;yes&#34; /&#62; tag in &#8230; <a
href="http://kosmaczewski.net/http-headers-web-apps-and-mobile-safari/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>I found today that Mobile Safari, the browser bundled with the iPhone, has a very strange and annoying behaviour when it comes to web apps. In fact, when you &#8220;install&#8221; web applications with the &lt;meta name=&quot;apple-mobile-web-app-capable&quot; content=&quot;yes&quot; /&gt;  tag in the &#8220;Home Screen&#8221;, <strong>the USER_AGENT header sent to the server is different to the one sent when you access the same app manually using Safari.</strong>.</p><p>Here&#8217;s a test that proves this assertion: <span
id="more-2047"></span></p><ol><li>Create a server-side web app with your preferred language, and <a
href="http://tonycode.com/wiki/index.php?title=Dumping_HTTP_Headers">print all the request headers</a>; for example, in PHP:
[source:php] <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html
xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta
http-equiv="content-type" content="text/html;charset=UTF-8" /><meta
name="apple-mobile-web-app-capable" content="yes" /></head><body> <?php
foreach($_SERVER as $h=>$v) {
if(ereg(&#8216;HTTP_(.+)&#8217;,$h,$hp)) {
echo &#8220;<li>$h = $v</li>\n&#8221;;
}
}
?></body></html> [/source]</li><li>Launch MobileSafari.app in either the iPhone Simulator or in your iPhone or iPod touch, and access the server-side script you created previously: <img
src="http://kosmaczewski.net/wp-content/uploads/2009/10/safari1.png" alt="safari1" title="safari1" width="480" height="320" class="alignnone size-full wp-image-2053" /></li><li>Add the application to your home screen, tapping the &#8220;+&#8221; button on the toolbar: <img
src="http://kosmaczewski.net/wp-content/uploads/2009/10/safari2.png" alt="safari2" title="safari2" width="480" height="320" class="alignnone size-full wp-image-2054" /></li><li>Now launch the application from your home screen, and this is what you see: <img
src="http://kosmaczewski.net/wp-content/uploads/2009/10/safari3.png" alt="safari3" title="safari3" width="480" height="320" class="alignnone size-full wp-image-2055" /></li><li>Compare the outputs (above, those from the latest iPhone Simulator, and below, those from my iPhone 3G with iPhone OS 3.1.2):<table
border="1" cellpadding="2" cellspacing="0"><tr><td><strong>Safari:</strong></td><td>HTTP_USER_AGENT = Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) <em>Version/4.0</em> Mobile/7D11 <em>Safari/528.16</em></td></tr><tr><td><strong>Home Screen App:</strong></td><td>HTTP_USER_AGENT = Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Mobile/7D11</td></tr></table> The texts in <em>italic</em> show the differences between the two outputs.</li></ol><p>This difference (in italic above) is only visible when the HTML generated by the server-side script contains the &lt;meta name=&quot;apple-mobile-web-app-capable&quot; content=&quot;yes&quot; /&gt;  tag, which triggers this change of behaviour. Otherwise, the outputs are exactly the same. Most annoyingly, this behavior is not documented (at least not that I am aware of). This problem <a
href="http://www.bennadel.com/blog/1197-Defaulting-To-The-Numeric-Keyboard-On-The-iPhone.htm">has already been spotted elsewhere</a> (scroll down until you see the comment by DVO published on Jul 3, 2009 at 7:34 AM; thanks to my friend <a
href="http://twitter.com/bdufresne">Bertrand</a> for the link!).</p><p>This is not only weird, but it also might break libraries used to generate iPhone-ready websites out of existing web apps (by redirecting the browser using the information in the USER_AGENT header; for example, this is what happens with the current version of the <a
href="http://github.com/noelrappin/rails-iui/">Rails iUI plugin</a> (which is why I found this behaviour :)</p><p>The lesson of all of this mess is this: if you have to test for Safari on the iPhone, do not use the word &#8220;Safari&#8221;, but rather use &#8220;AppleWebKit&#8221; and &#8220;Mobile&#8221;, to be sure of catching also the users who installed your application in their home screen.</p><p><strong>Update, 2009-10-30:</strong> In particular, the line of the Rails iUI plugin that causes problem with this particular behavior <a
href="http://github.com/noelrappin/rails-iui/blob/50c7c19038817d30b4c351232217c87a065d18a1/lib/iphone_controller.rb#L45">is this one</a>.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/http-headers-web-apps-and-mobile-safari/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>WordPress 2.8 and the get_link() error in line 647 of dashboard.php</title><link>http://kosmaczewski.net/wordpress-2-8-and-the-get_link-error-in-line-647-of-dashboard-php/</link> <comments>http://kosmaczewski.net/wordpress-2-8-and-the-get_link-error-in-line-647-of-dashboard-php/#comments</comments> <pubDate>Thu, 25 Jun 2009 17:22:08 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[How to?]]></category> <category><![CDATA[Open Source]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[wordpress]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1584</guid> <description><![CDATA[Wow, that&#8217;s a long title, but it should drive people with this problem right here. If you have upgraded your WordPress installation to 2.8, you might have encountered a nasty error in your Dashboard, which says something about a Fatal &#8230; <a
href="http://kosmaczewski.net/wordpress-2-8-and-the-get_link-error-in-line-647-of-dashboard-php/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Wow, that&#8217;s a long title, but it should drive people with this problem right here. If you have upgraded your WordPress installation to 2.8, you might have encountered a nasty error in your Dashboard, which says something about a</p><blockquote>Fatal error: Call to a member function on a non-object in /home/user/www/wp-admin/includes/dashboard.php on line 647</blockquote><p>This has been <a
href="http://wordpress.org/support/topic/279727">reported in the WordPress site</a> but no fix has been provided. <a
href="http://estanli.net/blog/2009/06/24/wordpress-2-8-problem-fatal-error-call-to-a-member-function-on-a-non-object/">I found elsewhere a possible fix</a>, but in my case, the new URL would not be saved at all, and the problem would persist.</p><p>I fixed it using a good old method, enabled by Open Source™: <strong>editing the code directly</strong>; I&#8217;m posting it here for those of you who would like to do it, until 2.8.1 is released:</p><p>[source:php:firstline(646)]
$author = $item->get_author();
if ($author == NULL)
{
$site_link = &#8220;&#8221;;
$publisher = &#8220;Someone&#8221;;
}
else
{
$site_link = esc_url(strip_tags($author->get_link()));
if ( !$publisher = esc_html(strip_tags($author->get_name())))
$publisher = __(&#8216;Somebody&#8217;);
if ($site_link)
$publisher = &#8220;<a
href='$site_link'>$publisher</a>&#8220;;
else
$publisher = &#8220;<strong>$publisher</strong>&#8220;;
}
[/source]</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/wordpress-2-8-and-the-get_link-error-in-line-647-of-dashboard-php/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>10 iPhone Memory Management Tips</title><link>http://akosma.com/2009/01/28/10-iphone-memory-management-tips/</link> <comments>http://akosma.com/2009/01/28/10-iphone-memory-management-tips/#comments</comments> <pubDate>Wed, 28 Jan 2009 12:00:58 +0000</pubDate> <dc:creator>akosma software</dc:creator> <category><![CDATA[Cocoa]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[How to?]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[Objective-C]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1324</guid> <description><![CDATA[Memory management in the iPhone is a hot topic. And since tonight I&#8217;m talking about it on tonight&#8217;s monthly meetup of the French-speaking Swiss iPhone Developers group, I might as well share some tips here from my own experience. I &#8230; <a
href="http://akosma.com/2009/01/28/10-iphone-memory-management-tips/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Memory management in the iPhone <a
href="http://www.mobileorchard.com/iphone-memory-management/">is a hot topic</a>. And since tonight I&#8217;m talking about it on tonight&#8217;s monthly meetup of the <a
href="http://www.facebook.com/group.php?gid=39755092833">French-speaking Swiss iPhone Developers group</a>, I might as well share some tips here from my own experience.</p><p>I won&#8217;t go dive through the basics; I think that Scott Stevenson did a great job in his <a
href="http://cocoadevcentral.com/d/learn_objectivec/">&#8220;Learn Objective-C&#8221; tutorial at CocoaDevCentral</a>, from where the image below comes. I&#8217;m just going to highlight some iPhone-specific issues here and there, and provide some hints on how to solve them.</p><p><a
href="http://cocoadevcentral.com/d/learn_objectivec/"><img
src="http://kosmaczewski.net/wp-content/uploads/2009/01/learnobjectivec-referencecounting.png" alt="" title="learnobjectivec-referencecounting" width="500" height="122" class="alignnone size-full wp-image-1325" /></a> <span
id="more-1324"></span> To begin with, some important background information:</p><ul><li>The <a
href="http://daringfireball.net/2008/10/iphone_3g">iPhone 3G has 128 MB of RAM</a>, but at least half of it might be used by the OS; this might leave as little as 40 MB to your application&#8230; but remember: you will get memory warnings even if you only use 3 MB;</li><li>The iPhone does not use garbage collection, even if it uses Objective-C 2.0 (which can use garbage collection on Leopard, nevertheless);</li><li>The basic memory management rule is: for every [ alloc | retain | copy ] you have to have a [ release ] somewhere;</li><li>The Objective-C runtime does not allow objects to be instantiated on the stack, but only on the heap; this means that you don&#8217;t have &#8220;automatic objects&#8221;, nor things like auto_ptr objects to help you manage memory;</li><li>You can use autorelease objects; but watch out! Since they are not released until their pool is released, they can become <em>de facto</em> memory leaks for you&#8230;;</li><li>The iPhone does not have a swap file, so forget about virtual memory. When there is no more memory, <strong>there is</strong> no more memory.</li></ul><p>Having said this, here&#8217;s my list of tips:</p><ul><li>Respond to Memory Warnings</li><li>Avoid Using Autoreleased Objects</li><li>Use Lazy Loading and Reuse</li><li>Avoid UIImage&#8217;s imageNamed:</li><li>Build Custom Table Cells and Reuse Them Properly</li><li>Override Setters Properly</li><li>Beware of Delegation</li><li>Use Instruments</li><li>Use a Static Analysis Tool</li><li>Use NSZombieEnabled</li></ul><h3>Respond to Memory Warnings</h3><p>Whatever you do in your code, please do not forget to respond to memory warnings! I can&#8217;t stress this much. I have seen application crashes just because the handler methods were not present on the controllers, which means that, even if you do not have anything to clear in your controller, at least do this:</p><p>[source:C]
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
[/source]</p><p>And you might as well respond to them on your application delegate, as follows:</p><p>[source:C]
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
[[ImageCache sharedImageCache] removeAllImagesInMemory];
}
[/source]</p><p>For the description of the ImageCache class, continue reading ;)</p><p>Or finally, as an NSNotification:</p><p>[source:C]
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(whatever:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
[/source]</p><h3>Avoid Using Autoreleased Objects</h3><p>Autoreleasing objects is easy and useful, but on the iPhone you should be careful with it. By default there is an NSAutoreleasePool instance created for you at the beginning of the main() function, <del
datetime="2009-02-26T15:21:04+00:00">but this pool is not cleared up until your application quits! This means that during runtime, your autoreleased objects are <em>de facto</em> memory leaks, since they are retained until the application quits.</del> <strong>(please see the comments below; I have experienced better performance when avoiding autoreleased objects, but my understanding of pools is misleading :)</strong></p><p>I started getting a better performance from my iPhone apps when I stopped using some methods creating autoreleased objects, for example:</p><p>[source:C]
// Instead of
NSString *string = [NSString stringWithFormat:@"value = %d", intVariable];</p><p>// use
NSString *string = [[NSString alloc] initWithFormat:@&#8221;value = %d&#8221;, intVariable];
&#8230;
[string release];
[/source]</p><p>In version 2.0 of the iPhone OS there was also the problem that some &#8220;convenience methods&#8221; did not work at all; I&#8217;m sure you&#8217;ve experienced your application crashing when using NSDictionary&#8217;s dictionaryWithObjects:forKeys: and then finding out that a replacing that with initWithObjects:forKeys: made your application run just fine. The NDA did not help at the time!</p><p>This does not mean that you can&#8217;t use autoreleased objects; you should use them, for example, when you have factory methods returning objects not owned neither by the factory nor by the client calling it. You can also use  autorelease pools in loops, when you need to allocate lots of small objects, but remember to release the pool right afterwards:</p><p>[source:C]
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (id item in array)
{
id anotherItem = [item createSomeAutoreleasedObject];
[anotherItem doSomethingWithIt];
}
[pool release];
[/source]</p><p>Remember to always release the pool in the same context where it was created. CocoaDev has an interesting discussion about <a
href="http://www.cocoadev.com/index.pl?NSAutoreleasePool">using NSAutoreleasePools in loops</a>.</p><p>Oh, and please, never release an autoreleased object on the iPhone: your application will crash almost instantly.</p><h3>Use Lazy Loading and Reuse</h3><p>If your application consists of several different controllers embedded into each other, defer their instantiation until the last possible moment; this means in practical terms that your init method is minimalistic, and that you do more stuff when you need it; the example below is a typical list + detail layout, using a UITableViewController subclass inside a UINavigationController:</p><p>[source:C]
@interface UITableViewControllerSubclass
{
@private
NSMutableArray *items;
DetailController *detailController;
UINavigationController *navigationController;
}
@end
[/source]</p><p>[source:C]
@implementation UITableViewControllerSubclass</p><h1>pragma mark -</h1><h1>pragma mark Constructors and destructors</h1><ul><li><p>(id)init
{
if (self = [self initWithStyle:UITableViewStylePlain])
{
// only basic stuff
items = [[NSMutableArray] alloc] initWithCapacity:20];
navigationController = [[UINavigationController alloc]
initWithRootViewController:self];
}
return self;
}</p></li><li><p>(void)dealloc
{
[items release];
[detailController release];
[navigationController release];
[super dealloc];
}</p></li></ul><p>// &#8230;</p><h1>pragma mark -</h1><h1>pragma mark UITableViewDelegate methods</h1><ul><li>(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Item *item = [items objectAtIndex:indexPath.row];
if (detailController == nil)
{
detailController = [[DetailController alloc] init];
}
detailController.item = item;
[self.navigationController
pushViewController:detailController
animated:YES];
}</li></ul><p>// &#8230;</p><p>@end
[/source]</p><p>As you can see in the example above, not only we are creating a DetailController instance only when needed (that is, when the user taps on an item in the UITableView), but we&#8217;re reusing it every time the user taps on another cell of the table; this has another benefit: a reduction of object allocation and instantiation, which also helps increasing performance a little bit.</p><p>You could also use UIViewController&#8217;s viewWillAppear: and viewDidDisappear: methods to perform some kind of lazy loading initialization and release, and if you really need to go further, you could use the UITabBarControllerDelegate&#8217;s tabBarController:didSelectViewController: method to load and unload parts of your application from memory, as you need it.</p><h3>Avoid UIImage&#8217;s imageNamed:</h3><p>Alex Curylo has written <a
href="http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/">an absolutely great article</a> about the problems with UIImage&#8217;s imageNamed: static method. It seems (and in my tests this appears to be true) that the iPhone OS (versions 2.0 and 2.1 at least) uses an internal cache for images loaded from disk using imageNamed:, and that in cases of low memory this cache is not cleared up completely (this seems to be corrected with version 2.2, though, but I cannot confirm).</p><p>Since I have projects that must run on version 2.0 of the iPhone OS, I have created a UIImage category with the following method:</p><p>[source:C]
@implementation UIImage (AKLoadingExtension)</p><ul><li>(UIImage *)newImageFromResource:(NSString *)filename
{
NSString *imageFile = [[NSString alloc] initWithFormat:@&#8221;%@/%@&#8221;,
[[NSBundle mainBundle] resourcePath], filename];
UIImage *image = nil;
image = [[UIImage alloc] initWithContentsOfFile:imageFile];
[imageFile release];
return image;
}</li></ul><p>@end
[/source]</p><p>The name of the method includes the word &#8220;new&#8221;, to comply with Objective-C&#8217;s naming guidelines, since the object we&#8217;re returning to the caller is not autoreleased and has a retain count of 1. The caller is then owner of the UIImage and responsible to release it.</p><p>Once I have this UIImage instance, I place it in an image cache with this interface:</p><p>[source:C]</p><h1>import <Foundation/Foundation.h></h1><p>@interface ImageCache : NSObject
{
@private
NSMutableArray *keyArray;
NSMutableDictionary *memoryCache;
NSFileManager *fileManager;
}</p><ul><li><p>(ImageCache *)sharedImageCache;</p></li><li><p>(UIImage *)imageForKey:(NSString *)key;</p></li><li>(BOOL)hasImageWithKey:(NSString *)key;</li><li>(void)storeImage:(UIImage *)image withKey:(NSString *)key;</li><li>(BOOL)imageExistsInMemory:(NSString *)key;</li><li>(BOOL)imageExistsInDisk:(NSString *)key;</li><li>(NSUInteger)countImagesInMemory;</li><li>(NSUInteger)countImagesInDisk;</li><li>(void)removeImageWithKey:(NSString *)key;</li><li>(void)removeAllImages;</li><li>(void)removeAllImagesInMemory;</li><li>(void)removeOldImages;</li></ul><p>@end
[/source]</p><p>Basically, ImageCache can be configured to have a fixed size in memory, and the images that were added first are removed first. It loads the images from the disk as required, keeping a copy in memory, and as suggested by Alex, you can remove them from memory in case of a warning:</p><p>[source:C]
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
[[ImageCache sharedImageCache] removeAllImagesInMemory];
}
[/source]</p><p>The complete source code of this ImageCache class, together with some unit tests (thanks to the <a
href="http://code.google.com/p/google-toolbox-for-mac/">Google Toolkit for Mac</a>), is available on the <a
href="/projects/iphone-image-cache/">Projects section of this blog</a> for you to download and play with.</p><h3>Build Custom Table Cells and Reuse Them Properly</h3><p>Remember to always use static NSString identifiers for your cells, which helps the UITableView class to reuse them and reduce memory consumption:</p><p>[source:C]
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Item *item = [items objectAtIndex:indexPath.row];
static NSString *identifier = @&#8221;ItemCell&#8221;;</p><pre><code>ItemCell *cell = (ItemCell *)[tableView
      dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
    cell = [[[ItemCell alloc] initWithIdentifier:identifier]
                                                    autorelease];
}
cell.item = item;
return cell;
</code></pre><p>}
[/source]</p><p>I also avoid using NIBs when working with table cells, for performance reasons. I prefer to draw the cells through my own subclasses of UITableViewCell, themselves using overridden setters for their properties, which takes me to the next point.</p><h3>Override Setters Properly</h3><p>As I said above, I tend to create my own subclasses of UITableViewCell, providing a simple property through which I change the model class holding the data that the cell is supposed to show. This has the effect of changing all the values of the fields and labels to the values corresponding to those of the model instance.</p><p>To do that, I override the setters as follows; for the following class definition&#8230;</p><p>[source:C]
@interface SomeClass
{
@private
NSArray *items;
NSString *name;
id<SomeProtocol> delegate;
}</p><p>@property (nonatomic, retain) NSArray *items;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) id<SomeProtocol> delegate;
@end
[/source]</p><p>&#8230; I use the following implementation:</p><p>[source:C]
@implementation SomeClass</p><p>@synthesize items;
@synthesize name;
@synthesize delegate;</p><ul><li>(void)dealloc
{
[items release];
[name release];
delegate = nil;
}</li></ul><h1>pragma mark -</h1><h1>pragma mark Overridden setters</h1><ul><li><p>(void)setItems:(NSArray *)obj
{
if (obj == items)
{
return;     // thanks Marco! (see comment #3 below)
}
[items release];
items = nil;
items = [obj retain];</p><p>if (items != nil)
{
// create the internal structure of the cell
// if not present, and change the widget values
}
}</p></li><li><p>(void)setName:(NSString *)obj
{
[name release];
name = nil;
name = [obj copy];   // I always copy NSStrings!</p><p>if (name != nil)
{
// create the internal structure of the cell
// if not present, and change the widget values
}
}</p></li><li><p>(void)setDelegate:(id<SomeProtocol>)obj
{
// do not retain! This is an &#8220;assign&#8221; property
delegate = obj;</p><p>if (delegate != nil)
{
// create the internal structure of the cell
// if not present, and change the widget values
}
}</p></li></ul><p>@end
[/source]</p><p>Overriding setters properly is important because you might be introducing memory leaks if done wrong. I usually copy all my NSString properties too, as a rule of thumb.</p><h3>Beware of Delegation</h3><p>If your code is delegate of some other object which you are about to release, remember to set its delegate property to nil before releasing it; otherwise, the object might &#8220;think&#8221; that its delegate is still there, and will send a message to an invalid pointer. To see what I&#8217;m talking about, consider this code:</p><p>[source:C]
@interface SomeClass <WidgetDelegate> {
@private
Widget *widget;
}
@end
[/source]</p><p>[source:C]
@implementation SomeClass</p><ul><li><p>(id)init
{
if (id = [super init])
{
widget = [[Widget alloc] init];
widget.delegate = self;
}
return self;
}</p></li><li><p>(void)dealloc
{
// widget might be retained by someone else!
widget.delegate = nil;
[widget release];
[super dealloc];
}</p></li></ul><h1>pragma mark -</h1><h1>pragma mark WidgetDelegate methods</h1><ul><li>(void)widget:(Widget *)obj callsItsDelegate:(BOOL)value
{
// and here something happens&#8230;
}</li></ul><p>@end
[/source]</p><p>SomeClass is delegate of Widget. Widget instances might be retained by someone else, which means that even after the release message in the dealloc method, widget might still be alive and call its delegate; if this variable is not nil, widget will send a message to a non-existent object, which will surely crash your application.</p><h3>Use Instruments</h3><p>The &#8220;Leaks&#8221; instrument is your friend, and you should use it after you write the first line of code. Typically, I launch it every time before doing a checkin of some new code. In Xcode, select &#8220;Run / Start with Performance Tool / Leaks&#8221; and you&#8217;re done. You can use it in the simulator or on your device.</p><h3>Use a Static Analysis Tool</h3><p>Use the <a
href="http://clang.llvm.org/StaticAnalysis.html">LLVM/Clang Static Analyzer</a> tool. This amazing tool will catch naming errors (regarding the Objective-C naming conventions) and some hidden memory leaks, which are particularly nasty when using CoreFoundation libraries (Address Book, sound, CoreGraphics, etc). You can add it to your daily build script, it&#8217;s very easy to use.</p><p>But you must use it. Enough said.</p><h3>Use NSZombieEnabled</h3><p>Lou Franco has posted an <a
href="http://loufranco.com/blog/files/debugging-memory-iphone.html">excellent article about how to use NSZombieEnabled</a> in your development cycle. The idea is to be able to find which messages are being sent to invalid pointers, referencing objects which have been released somewhere in your code. Always remember who&#8217;s the owner of your objects, and check for existence elsewhere!</p><h3>And You?</h3><p>How about you? What are your tips or best practices you usually use for your iPhone apps? Feel free to share them in the form below.</p><p><strong>Update, 2009-01-29:</strong> I am overwhelmed with the response and traffic that this post has gotten so far! Yesterday evening I had the pleasure of discussing this subject with the guys of the iPhone Developers Facebook group, and I got interesting remarks from Marco Scheurer from <a
href="http://www.sente.ch/">Sen:te</a> (including a comment below), which I&#8217;ve added to this post today.</p><p>Oh, and by the way, <a
href="/projects/iphone-memory-management-tips/">I&#8217;ve uploaded the slides here!</a> They have a Creative Commons license, so feel free to use them if you find them useful.</p> ]]></content:encoded> <wfw:commentRss>http://akosma.com/2009/01/28/10-iphone-memory-management-tips/feed/</wfw:commentRss> <slash:comments>33</slash:comments> </item> <item><title>Basic vs. Digest</title><link>http://kosmaczewski.net/basic-vs-digest/</link> <comments>http://kosmaczewski.net/basic-vs-digest/#comments</comments> <pubDate>Mon, 07 Jul 2008 15:46:01 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[How to?]]></category> <category><![CDATA[Papers]]></category> <category><![CDATA[Technology]]></category> <category><![CDATA[design]]></category> <category><![CDATA[HTTP]]></category> <category><![CDATA[Opinion]]></category> <category><![CDATA[web]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1226</guid> <description><![CDATA[In the series of highly boring posts ;) here&#8217;s another one; in this case, a simple explanation of two different authentication protocols available in the HTTP standard. HTTP Basic Authentication Protocol This is the simplest HTTP Authentication protocol available: The &#8230; <a
href="http://kosmaczewski.net/basic-vs-digest/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>In the series of highly boring posts ;) here&#8217;s another one; in this case, a simple explanation of two different authentication protocols available in the HTTP standard.</p><p><img
src="http://kosmaczewski.net/wp-content/uploads/2008/07/login.png" alt="" title="login" width="497" height="209" class="alignnone size-full wp-image-1227" /></p><p><strong>HTTP Basic Authentication Protocol</strong></p><p>This is the simplest HTTP Authentication protocol available:</p><ol><li>The browser sends a request to a protected resource:  GET /index.html</li><li>The server looks for the &#8220;Authenticated&#8221; header in the request; since it does not find it, it replies back with a response with the 401 code (&#8220;Unauthorized&#8221;). The response contains a &#8220;WWW-Authenticate&#8221; header, with the value &#8220;Basic&#8221;. This response is called a &#8220;challenge&#8221;, and it also contains a &#8220;realm&#8221; text, which describes the protected resource in clear text (the &#8220;realm&#8221; is shown in the pop-up window that usually appears for you to type your password when this protocol is used).</li><li>The browser creates a new request  GET /index.html  that contains an HTTP_AUTHORIZATION header, whose value is the word &#8220;Basic&#8221; followed by the &#8216;username:password&#8217; string encoded in base 64. This algorithm is a two-way algorithm: you can retrieve the username and password from the base 64-encoded string.</li><li>The server receives this response, and since base 64 is a two-way algorithm, it compares the MD5 (or SHA1) password hash to the one stored in the database. If they are the same, the request is processed. Otherwise, the user gets a 401 again.</li></ol><p><span
id="more-1226"></span> The advantage of this protocol is that it is simpler to implement, but the tradeoff is that any malicious user sniffing on the network can retrieve the username:password combo and use the base 64 algorithm to get the original values. All of this makes this protocol relatively insecure.</p><p><strong>HTTP Digest Authentication Protocol</strong></p><p>Simply put, the HTTP Digest Authentication protocol goes like this:</p><ol><li>The browser sends a request to a protected resource:  GET /index.html</li><li>The server looks for the &#8220;Authenticated&#8221; header in the request; since it does not find it, it replies back with a response with the 401 code (&#8220;Unauthorized&#8221;). The response contains a &#8220;WWW-Authenticate&#8221; header, with the value &#8220;Digest&#8221; followed by two long MD5 strings (&#8220;nonce&#8221; and &#8220;opaque&#8221;) generated specifically for this request, and that the browser will use to answer back to the server. This response is called a &#8220;challenge&#8221;, and it also contains a &#8220;realm&#8221; text, which describes the protected resource in clear text (the &#8220;realm&#8221; is shown in the pop-up window that usually appears for you to type your password when this protocol is used).</li><li>The browser creates a new request  GET /index.html  but this time it will not send the username/password combo in clear text (like in the case of HTTP Basic Authentication): it will &#8220;hash&#8221; this information, together with the &#8220;nonce&#8221; and &#8220;opaque&#8221; values received from the server, together with the &#8220;realm&#8221;, using the MD5 hashing algorithm. This is a username/realm/password hash, so to speak.</li><li>The server receives this response, and since MD5 is a one-way algorithm (you cannot, theoretically, find the original password from all the blah-blah sent in step 3), it compares the username/realm/password hash to the one stored in the database. If they are the same, the request is processed. Otherwise, the user gets a 401 again.</li></ol><p>The advantage of the HTTP Digest Authentication protocol is that the key exchange between client and server is done in encrypted hashes. Even better, the server does not store the password per se, but a complex mix of strings all hashed together. This makes the protocol a very secure option, but at the same time, it requires more processing time and code to execute.</p><p>However, the HTTP Digest Authentication protocol implies several design issues:</p><ol><li>The username/realm/password combo is encoded and stored using the &#8220;realm&#8221; string. So this means that if the realm changes, all the passwords become invalid. And since MD5 is a &#8220;one-way&#8221; algorithm, you cannot retrieve the passwords, and your users must retype them. Be careful!</li><li>Since the default user classes in most web programming toolkits (Django, Rails, etc) just store an MD5 (or SHA1) hash of the password, to use HTTP Digest Authentication you must have a separate database field, somewhere, to store the username/realm/password combo hash.</li></ol> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/basic-vs-digest/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>wp-super-cache problem? Easy fix</title><link>http://kosmaczewski.net/wp-super-cache-problem-easy-fix/</link> <comments>http://kosmaczewski.net/wp-super-cache-problem-easy-fix/#comments</comments> <pubDate>Wed, 23 Apr 2008 20:51:44 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[How to?]]></category> <category><![CDATA[Open Source]]></category> <category><![CDATA[wordpress]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1155</guid> <description><![CDATA[I&#8217;ve just installed the excellent wp-super-cache plugin to accelerate things a bit in this blog; today somebody sent one of my pages to reddit and I&#8217;ve had more users than usual! &#8211; by the way, thanks for coming! :) Update: &#8230; <a
href="http://kosmaczewski.net/wp-super-cache-problem-easy-fix/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p><img
src="http://kosmaczewski.net/wp-content/uploads/2008/04/wp.png" alt="" title="wp" width="325" height="75" hspace="10" vspace="10" align="right" />I&#8217;ve just installed the excellent <a
href="http://wordpress.org/extend/plugins/wp-super-cache/">wp-super-cache plugin</a> to accelerate things a bit in this blog; today somebody sent one of my pages to reddit and I&#8217;ve had more users than usual! &#8211; by the way, thanks for coming! :)</p><p><strong>Update:</strong> I admit, it also has a bit to do with the reading of <a
href="http://www.codinghorror.com/blog/archives/001105.html">today&#8217;s entry in Coding Horror</a> ;) But I love WordPress nonetheless. I prefer it over MovableType (which I used during one year and a half).</p><p>The only glitch was: <strong>at first, it didn&#8217;t work</strong>. I think you know the feeling.</p><p>The plugin was enabled, everything was activated, yet no files were cached: <a
href="http://wordpress.org/support/topic/161744?replies=25">exactly this same problem</a>. And I found a quick fix to it, hence this post: fire your <a
href="http://www.panic.com/transmit/">FTP client of choice</a> and go to /wp-content/cache. If you don&#8217;t see a &#8220;supercache&#8221; folder in there, just create it. Magically, if you have some traffic on your blog and you dig in that folder a couple of seconds later you&#8217;ll see already lots of files! No need to modify .htaccess whatsoever.</p><p>If you want to populate it, log out of the WordPress admin and start clicking on your blog. This plugin only creates cached files for anonymous visitors! I also turned on the compression so you should start having faster response times.</p><p>It was the only thing to do manually to get it working. Hope this helps! Any comments, as usual, more than welcome.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/wp-super-cache-problem-easy-fix/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Installing PostgreSQL 8.3 on Leopard</title><link>http://kosmaczewski.net/postgresql-leopard/</link> <comments>http://kosmaczewski.net/postgresql-leopard/#comments</comments> <pubDate>Wed, 23 Apr 2008 15:40:24 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Django]]></category> <category><![CDATA[How to?]]></category> <category><![CDATA[Open Source]]></category> <category><![CDATA[Ruby on Rails]]></category> <category><![CDATA[PostgreSQL]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1152</guid> <description><![CDATA[This is the documented path to my discovery of PostgreSQL 8.3, which I&#8217;ve never used before. Now that MySQL&#8216;s community is getting hammered to death by Sun, and thanks to all the good things I&#8217;ve heard about it over the &#8230; <a
href="http://kosmaczewski.net/postgresql-leopard/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p><a
href="http://www.postgresql.org/"><img
src="http://kosmaczewski.net/wp-content/uploads/2008/04/postgre_logo.png" alt="" title="postgre_logo" width="228" height="56" align="left" hspace="10" vspace="5" border="0" /></a>This is the documented path to my discovery of <a
href="http://www.postgresql.org/">PostgreSQL 8.3</a>, which I&#8217;ve never used before. Now that <a
href="http://mysql.com/">MySQL</a>&#8216;s community is getting <a
href="http://blog.wired.com/monkeybites/2008/04/community-cries.html">hammered to death by Sun</a>, and thanks to all the good things I&#8217;ve heard about it over the years (including enhanced performance on multicore systems and greater scalability), I really wanted to install it and play with it.</p><p>Frankly, it&#8217;s not easy. At all (actually this is why I think MySQL is so popular, because of the ease of installation!) So hang tight and read on. <span
id="more-1152"></span></p><h2>Installation</h2><p><a
href="http://www2.russbrooks.com:8080/2007/11/4/install-postgresql-on-mac-os-x-10-5-leopard">Russ Brooks says it is better to avoid</a> <a
href="http://www.macports.org/">MacPorts</a>: I must say that indeed, I tried installing PostgreSQL with MacPorts and I got seriously stuck, unable to do anything with it, not even starting the server. So I uninstalled the PostgreSQL MacPorts package and found other options: a <a
href="http://www.postgresqlformac.com/">PostgreSQL for Mac</a> installer, and <a
href="http://www.entropy.ch/software/macosx/postgresql/">Marc Liyanage&#8217;s own installer</a>. I decided to go with the first one, since Marc&#8217;s installs version 8.1 of the server, and PostgreSQL for Mac offers version 8.3.</p><p>The installation goes without trouble, using a standard installer (which means that you need administrative privileges, as usual). However, you want to read <a
href="http://www2.russbrooks.com:8080/2007/11/4/install-postgresql-on-mac-os-x-10-5-leopard">these explanations</a> before doing anything  ;)</p><p>NOTE: if you have trouble installing PostgreSQL using the above installer (as I did after the unsuccessful MacPorts installation / desinstallation), open Terminal.app and try these commands:</p><p><code>$ sudo dscl localhost
&gt;cd Local/Default/Users/
&gt;ls </code></p><p>If you see a &#8220;postgres&#8221; entry in the list of local users, delete it and re-run the installer:</p><p><code>&gt;delete postgres</code></p><h2>After the Installation</h2><p>The installer puts the PostgreSQL installation into /Library/PostgreSQL8. You should add the path to the PostgreSQL binaries in your PATH environment variable before doing anything else:</p><p><code>export PATH=/Library/PostgreSQL8/bin:$PATH (bash)
setenv PATH /Library/PostgreSQL8/bin:$PATH (tcsh)</code></p><p>Then, type the following commands to create the default database, owned by the &#8220;postgres&#8221; user:</p><p><code>cd /Library/PostgreSQL8/
sudo rm -r data
sudo mkdir data
sudo chown postgres:postgres data
cd bin
sudo -u postgres initdb -E utf8 /Library/PostgreSQL8/data </code></p><p>In my case (Leopard-powered PowerBook G4) I had the &#8220;Shared Memory error&#8221; that Russ talks about. So I followed his advice: I created a file named /etc/sysctl.conf with the following contents, then rebooted my computer and everything went fine:</p><p><code>kern.sysv.shmmax=4194304
kern.sysv.shmmin=1
kern.sysv.shmmni=32
kern.sysv.shmseg=8
kern.sysv.shmall=1024 </code></p><p>I also used dscl to change the password of the postgres user (otherwise, how to know which is it??)</p><p><code>&gt;passwd postgres postgres</code></p><p><img
src="http://kosmaczewski.net/wp-content/uploads/2008/04/postgre_apps.png" alt="" title="postgre_apps" width="448" height="494" class="aligncenter size-full wp-image-1153" /></p><p>The installer adds some handy utilities on your /Application folder (see the image above). You can also use <a
href="http://www.pgadmin.org/">pgAdmin</a> to manage the database server. Very handy. I tried to use <a
href="http://phppgadmin.sourceforge.net/">phpPgAdmin</a> but without success (can&#8217;t get past the login screen&#8230; :(</p><p>And that&#8217;s it! There are interesting resources out there explaining how to use it from <a
href="http://wiki.rubyonrails.org/rails/pages/PostgreSQL">Rails</a> or <a
href="http://www.djangoproject.com/documentation/install/">Django</a>, so I&#8217;ll start reviewing them&#8230;</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/postgresql-leopard/feed/</wfw:commentRss> <slash:comments>8</slash:comments> </item> <item><title>Extracting e-mails from a vCard file with Python</title><link>http://kosmaczewski.net/extracting-emails-vcard-python/</link> <comments>http://kosmaczewski.net/extracting-emails-vcard-python/#comments</comments> <pubDate>Wed, 23 Apr 2008 10:39:46 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[How to?]]></category> <category><![CDATA[Python]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1151</guid> <description><![CDATA[Let&#8217;s say that you have a vCard file. You can export it from your Mac OS X AddressBook.app, or from any other similar application. Now you need to extract some information from it, namely the e-mails, for spamming your friends &#8230; <a
href="http://kosmaczewski.net/extracting-emails-vcard-python/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Let&#8217;s say that you have a <a
href="http://en.wikipedia.org/wiki/VCard">vCard</a> file. You can export it from your Mac OS X AddressBook.app, or from any other similar application. Now you need to extract some information from it, namely the e-mails, for spamming your friends with some boring news. Typical.</p><p>Enter <a
href="http://vobject.skyhouseconsulting.com/">vobject</a>. This Python library is part of the <a
href="http://chandlerproject.org/">Chandler</a> effort (which seems to be somewhat ill-fated since <a
href="http://www.cnet.com/8301-13505_1-9847739-16.html">Mitch Kapor announced he was leaving the project</a>). Anyway, you can download this library <a
href="http://vobject.skyhouseconsulting.com/vobject-0.6.0.tar.gz">from here</a> and then install it using the common sequence:</p><p><code>python setup.py build
python setup.py install </code></p><p>Finally, here&#8217;s a bit of code to quickly extract the names and e-mail addresses from a vCard file called &#8220;vCards.vcf&#8221; containing lots of vCard instances, one after the other (AddressBook.app exports data this way, instead of creating on file per contact):</p><p>[source:python]
import vobject</p><p>f = open(&#8220;vCards.vcf&#8221;)
s = &#8220;&#8221;.join(f.readlines())
f.close()</p><p>a = vobject.readComponents(s)</p><p>counter = 0</p><p>while True:
try:
# &#8220;next()&#8221; seems to throw an exception
# when there aren&#8217;t any more &#8220;Components&#8221;
# in the stream&#8230;
# Talk about nice flow control!
b = a.next()
counter += 1
if b.contents.has_key(&#8216;email&#8217;):
# &#8220;repr()&#8221; below avoids
# unicode &#8211;> ascii exceptions
print repr(b.fn.value), repr(b.email.value)
except:
break</p><p>print &#8220;%d e-mails found.&#8221; % counter
[/source]</p><p><a
href="http://vobject.skyhouseconsulting.com/epydoc/">The library documentation</a>, to put it simply, isn&#8217;t as good as the library itself (see? I can be politically correct sometimes :) Maybe I missed a better way to iterate over the contents of the whole stream of vCard instances inside the file (using exceptions for that is yuck!), but then again, feel free to add your comments below as usual.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/extracting-emails-vcard-python/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Quick spec from your Python tests</title><link>http://kosmaczewski.net/quick-spec-for-python-tests/</link> <comments>http://kosmaczewski.net/quick-spec-for-python-tests/#comments</comments> <pubDate>Thu, 17 Apr 2008 16:25:58 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Django]]></category> <category><![CDATA[How to?]]></category> <category><![CDATA[Quality]]></category> <category><![CDATA[Python]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1148</guid> <description><![CDATA[Using Python&#8217;s own unittest package, here&#8217;s a small script that can iterate over your test suite to output a small, quick, nice list of the tests in your application: [source:python] import unittest loader = unittest.TestLoader() tests = loader.loadTestsFromName(&#8216;path.to.your.tests.package&#8217;) for test &#8230; <a
href="http://kosmaczewski.net/quick-spec-for-python-tests/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Using Python&#8217;s own unittest package, here&#8217;s a small script that can iterate over your test suite to output a small, quick, nice list of the tests in your application:</p><p>[source:python]
import unittest</p><p>loader = unittest.TestLoader()
tests = loader.loadTestsFromName(&#8216;path.to.your.tests.package&#8217;)
for test in tests.<em>tests:
print test._tests[0].<strong>class</strong>.<strong>name</strong>.replace(&#8220;Test&#8221;, &#8220;&#8221;)
for method in test._tests:
print &#8221;   %s&#8221; % method._testMethodName.replace(&#8220;test</em>&#8220;, &#8220;&#8221;).capitalize().replace(&#8220;_&#8221;, &#8221; &#8220;)
[/source]</p><p>This would yield something like this: <code> Business
&nbsp;&nbsp;&nbsp;&nbsp;Accounts have at least one entry
&nbsp;&nbsp;&nbsp;&nbsp;Clerks cannot close accounts
Security
&nbsp;&nbsp;&nbsp;&nbsp;Users can create new accounts
&nbsp;&nbsp;&nbsp;&nbsp;Anonymous users cannot access private areas
... </code></p><p>Of course, you&#8217;ll get better results if you follow <a
href="http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html">Google&#8217;s naming conventions</a> for your tests&#8230; ;) This is not <a
href="http://rspec.info/">rspec</a> (nor an alternative to it) but it might be useful to some of you.</p><p>Just as a reminder for Django users: you might need to</p><p><code> setenv DJANGO_SETTINGS_MODULE application.settings </code></p><p>or</p><p><code> export DJANGO_SETTINGS_MODULE=application.settings </code></p><p>in order to make the script work properly! At least I had to :)</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/quick-spec-for-python-tests/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>How to build ohcount on Leopard</title><link>http://kosmaczewski.net/build-ohcount-leopard/</link> <comments>http://kosmaczewski.net/build-ohcount-leopard/#comments</comments> <pubDate>Mon, 07 Apr 2008 11:12:07 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Apple]]></category> <category><![CDATA[How to?]]></category> <category><![CDATA[Open Source]]></category> <category><![CDATA[Leopard]]></category> <category><![CDATA[Ruby]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1142</guid> <description><![CDATA[If you do not know ohcount, you should; the guys at ohloh.net have GPL&#8217;d one of their core components, namely the one that allows you to perform source code line counts in your own projects. Neat and useful! However, the &#8230; <a
href="http://kosmaczewski.net/build-ohcount-leopard/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>If you do not know <a
href="http://labs.ohloh.net/ohcount">ohcount</a>, you should; the guys at <a
href="http://www.ohloh.net/">ohloh.net</a> have GPL&#8217;d one of their core components, namely the one that allows you to perform source code line counts in your own projects. Neat and useful!</p><p>However, the current ohcount distribution (which you can download from <a
href="http://labs.ohloh.net/download/ohcount-1.0.0.tar.gz">this link</a>) does not build out-of-the-box in Leopard. Here&#8217;s how I made it work in my own Leopard G4 PowerBook (PPC) computer. <span
id="more-1142"></span></p><ul><li>Download <a
href="http://downloads.sourceforge.net/pcre/pcre-7.6.tar.gz">pcre-7.6.tar.gz from SourceForge</a></li><li>Extract the file into the &#8220;pcre-7.6&#8243; folder</li><li>cd into the pcre-7.6 folder and <code>./configure
make
sudo make install</code></li><li>Download <a
href="http://labs.ohloh.net/download/ohcount-1.0.0.tar.gz">ohcount-1.0.0.tar.gz from Ohloh</a></li><li>Extract the file into the &#8220;ohcount-1.0.0&#8243; folder</li><li>cd into the ohcount-1.0.0 folder and open &#8220;Rakefile&#8221; with your favorite editor; modify line 73 as follows:</li></ul><p>[source:ruby::firstline(68)]
file &#8220;#{EXT_DIR}/Makefile&#8221; => &#8220;#{EXT_DIR}/extconf.rb&#8221; do
cd EXT_DIR do
if ENV['DEBUG']
ruby &#8216;extconf.rb&#8217;, &#8216;debug&#8217;
else
ENV['ARCHFLAGS'] = &#8220;-arch ppc&#8221;
# or &#8220;-arch i386&#8243; if you use an Intel Mac
ruby &#8216;extconf.rb&#8217;
end
end
end
[/source]</p><ul><li>Now cd into the ohcount-1.0.0 folder and <code>rake</code> the project. You should see a series of tests running, with the final message saying &#8220;92 tests, 321 assertions, 0 failures, 0 errors&#8221;.</li><li>Now you can use the bin/ohcount binary to get statistics from your source code!</li></ul><p>The root of the problem is that Leopard&#8217;s Ruby installation is a &#8220;Universal Binary&#8221;, while the pcre library is built as a native binary only; hence, it does not link for the i386 binary, hence, it does not work. Another solution, I think, would be to compile pcre as a Universal Binary, but I leave this as an exercise to the reader :)</p><p>I found the fix thanks to <a
href="http://www.ohloh.net/forums/3493/topics/1152">this conversation in Ohloh&#8217;s forum</a>, which took me to <a
href="http://readlist.com/lists/ruby-lang.org/ruby-talk/19/95220.html">this thread on ruby-talk</a> and finally <a
href="http://trac.macosforge.org/projects/ruby/wiki/WhatsNewInLeopard#Ruby">this wiki page in MacOS Forge</a>.</p><p>Hope this helps!</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/build-ohcount-leopard/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Playing with HTTP libraries</title><link>http://kosmaczewski.net/playing-with-http-libraries/</link> <comments>http://kosmaczewski.net/playing-with-http-libraries/#comments</comments> <pubDate>Wed, 26 Mar 2008 22:28:31 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Code]]></category> <category><![CDATA[How to?]]></category> <category><![CDATA[HTTP]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[libraries]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[programming]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[Ruby]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/2008/03/26/playing-with-http-libraries/</guid> <description><![CDATA[It&#8217;s fun to find out how to tackle the same task in different programming languages; in this case, it&#8217;s all about doing HTTP requests over a network: fortunately, there are networking libraries in virtually all major programming languages. In my &#8230; <a
href="http://kosmaczewski.net/playing-with-http-libraries/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>It&#8217;s fun to find out how to tackle the same task in different programming languages; in this case, it&#8217;s all about doing HTTP requests over a network: fortunately, there are networking libraries in virtually all major programming languages. In my current project, I&#8217;m generating wrappers easing the access to the core of the project itself, a RESTful API. This way, developers interested in using the API can just take a wrapper, include it in their projects, and start coding right away. No need to know this (relatively low-level) stuff; just use the API. The wrappers themselves are auto-generated from the API definition itself, but that&#8217;s another story ;)</p><p>Below there is a sample of the different ways I&#8217;ve found to do a network access to a remote server, using HTTP Basic Authentication and a couple of headers, in PHP, Ruby, Python, JavaScript, and even Objective-C! I&#8217;m even generating ActionScript 3.0 code, but I&#8217;m not a Flash coder :) So I&#8217;ll post the wrappers that work best at the moment, and in the future I&#8217;ll include other examples, particularly for .NET, C++ and Java.</p><p>In all the cases below, there is a &#8220;request&#8221; function or method that takes an HTTP verb (GET, POST, PUT, DELETE, etc), a URL (without the slash &#8220;/&#8221; at the beginning) and some parameter data, in the form of a dictionary. The function wraps the underlying libraries of each programming language, offering a simpler interface, and allowing for HTTP Basic Authentication (for HTTP Digest Authentication it would be much, much more complex!). There are synchronous (useful for server or command-line applications) and asynchronous versions (for GUI systems). Off to the code! <span
id="more-1137"></span> In PHP (synchronous):</p><p>[source:php]
$conf = array(
&#8220;server&#8221; => &#8220;localhost&#8221;,
&#8220;username&#8221; => &#8220;&#8221;,
&#8220;password&#8221; => &#8220;&#8221;
);</p><p>function request($verb, $url, $parameters = array()) {
global $conf;
$headers = array(
&#8220;Content-Type: text/html; charset=utf-8&#8243;,
&#8220;Accept: application/javascript&#8221;,
&#8220;Cache-Control: no-cache&#8221;,
&#8220;Pragma: no-cache&#8221;,
&#8220;Content-length: &#8221; . strlen($xml_data),
&#8220;Authorization: Basic &#8221; . base64_encode($conf["username"] . &#8220;:&#8221; . $conf["password"])
);</p><p>$path = $conf["server"] . &#8220;/&#8221; . $url;
$conn = curl_init();
curl_setopt($conn, CURLOPT_URL, $path);
curl_setopt($conn, CURLOPT_HTTPHEADER, $headers);
curl_setopt($conn, CURLOPT_USERAGENT, &#8220;Identify yourself!&#8221;);
curl_setopt($conn, CURLOPT_CUSTOMREQUEST, strtoupper($verb));
curl_setopt($conn, CURLOPT_POSTFIELDS, $xml_data);
curl_setopt($conn, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($conn);
$code = curl_getinfo($conn, CURLINFO_HTTP_CODE);</p><p>if($code == 200 &amp;&amp; strtoupper($verb) == &#8220;GET&#8221;) {
return json_decode($data);
}
else {
return $data;
}</p><p>curl_close($conn);</p><p>return $data;
}
[/source]</p><p>The <a
href="http://ch2.php.net/curl">curl library</a> has a distinctive C smell :) The good thing is that after doing this wrapper, doing the C++ one will be fairly straightforward!</p><p>In Ruby (synchronous):</p><p>[source:ruby]
require &#8216;net/http&#8217;
require &#8216;uri&#8217;
require &#8216;json&#8217;</p><p>$conf = {
&#8220;server&#8221; => &#8220;localhost&#8221;,
&#8220;username&#8221; => &#8220;&#8221;,
&#8220;password&#8221; => &#8220;&#8221;
}</p><p>def request(verb, url, parameters = nil)
Net::HTTP.start($conf["server"]) do |http|
headers = {
&#8220;Accept&#8221; => &#8220;application/javascript&#8221;,
&#8220;User-Agent&#8221; => &#8220;Identify yourself!&#8221;
}
path = &#8220;/&#8221; + url
req = nil
case verb.upcase
when &#8220;GET&#8221;:
req = Net::HTTP::Get.new(path, headers)
when &#8220;POST&#8221;:
req = Net::HTTP::Post.new(path, headers)
when &#8220;PUT&#8221;:
req = Net::HTTP::Put.new(path, headers)
when &#8220;DELETE&#8221;:
req = Net::HTTP::Delete.new(path, headers)
else
raise Exception.new(&#8220;Invalid HTTP verb&#8221;)
end
req.basic_auth $conf["username"], $conf["password"]
req.set_form_data(parameters) if not parameters == nil
response = http.request(req)
if response.code == &#8220;200&#8243; &amp;&amp; verb.upcase == &#8220;GET&#8221;
JSON.parse(response.body)
else
print response.code + &#8221; &#8221; + response.message + &#8221; &#8221; + response.body
end
end
end
[/source]</p><p>The Ruby library is the only one I found so far that features the four HTTP verbs in the interface!</p><p>In Python (synchronous):</p><p>[source:python]
import simplejson
import httplib, urllib
import base64</p><p>conf = {
&#8220;server&#8221;: &#8220;localhost&#8221;,
&#8220;username&#8221;: &#8220;&#8221;,
&#8220;password&#8221;: &#8220;&#8221;,
}</p><p>def request(verb, url, parameters = {}):
params = urllib.urlencode(parameters)
base64string = base64.encodestring(&#8216;%s:%s&#8217; % (conf["username"], conf["password"]))[:-1]
headers = {
&#8220;Accept&#8221;: &#8220;application/javascript&#8221;,
&#8220;Authorization&#8221;: &#8220;Basic %s&#8221; % base64string,
&#8220;User-Agent&#8221;: &#8220;Identify yourself!&#8221;,
}
conn = httplib.HTTPConnection(conf["server"])
conn.request(verb.upper(), &#8220;/&#8221; + url, params, headers)
response = conn.getresponse()
if response.status == 200 and verb.upper() == &#8220;GET&#8221;:
obj = simplejson.loads(response.read())
return obj
else:
print response.status, response.reason, response.read()
conn.close()
[/source]</p><p>I much prefer the Ruby way, if you ask me. I don&#8217;t know, it&#8217;s more elegant. I can&#8217;t get used to the indenting!</p><p>In JavaScript, using Prototype (asynchronous):</p><p>[source:javascript]
var conf = {
server: &#8220;localhost&#8221;,
username: &#8220;&#8221;,
password: &#8220;&#8221;
};
var request = function(verb, url, parameters, successHandler, errorHandler) {
// A really ugly way to do HTTP Basic Auth, I know :)
var api_url = ["http://", conf.username.replace(/@/, "%40"), ":", conf.password, "@", conf.server, "/", url].join(&#8220;&#8221;);</p><pre><code>new Ajax.Request(api_url, {
    method: verb.toLowerCase(),
    parameters: parameters,
    requestHeaders: {
        "Accept": "application/javascript",
        "Cache-Control": "no-cache",
        "Pragma": "no-cache",
        "Content-Type": "text/html; charset=utf-8"
    },
    onSuccess: function(transport) {
        if(successHandler) successHandler(transport);
    },
    onFailure: function(transport) {
        if(errorHandler) errorHandler(transport);
    }
});
</code></pre><p>};
[/source]</p><p>Again in JavaScript, but this time using jQuery (asynchronous):</p><p>[source:javascript]
var conf = {
server: &#8220;localhost&#8221;,
username: &#8220;&#8221;,
password: &#8220;&#8221;
};
var request = function(verb, url, parameters, successHandler, errorHandler) {
var api_url = ["http://", conf.username.replace(/@/, "%40"), ":", conf.password, "@", conf.server,"/", url].join(&#8220;&#8221;);</p><pre><code>$.ajax({
    type: verb.toUpperCase(),
    url: api_url,
    async: true,
    data: parameters,
    cache: false,
    // jQuery does not allow to change headers otherwise (?) than using the beforeSend() hook:
    beforeSend: function(xhr) {
        xhr.setRequestHeader("Content-Type", "text/html; charset=utf-8");
        xhr.setRequestHeader('Accept', 'application/javascript');
        xhr.setRequestHeader('Cache-Control', 'no-cache');
        xhr.setRequestHeader('Pragma', 'no-cache');
    },
    complete: function(engine, textStatus) {
        if (engine.readyState == 4) {
            if (engine.status == 200 || engine.status == 201) { if(successHandler) successHandler(engine); }
            else { if(errorHandler) errorHandler(engine); }
        }
    }
});
</code></pre><p>};
[/source]</p><p>The last JavaScript one, but this time using bare bones XMLHttpRequest (asynchronous):</p><p>[source:javascript]
var conf = {
server: &#8220;localhost&#8221;,
username: &#8220;&#8221;,
password: &#8220;&#8221;
};
var request = function(verb, url, parameters, successHandler, errorHandler) {
var api_url = ["http://", conf.username.replace(/@/, "%40"), ":", conf.password, "@", conf.server,"/", url].join(&#8220;&#8221;);</p><pre><code>var params = [];
for(var item in parameters) {
    params.push(escape(item) + "=" + escape(parameters[item]));
}
var engine = null;
if (window.XMLHttpRequest) {
    engine = new XMLHttpRequest();
}
if (window.ActiveXObject) {
    engine = new ActiveXObject("Microsoft.XMLHTTP");
}
engine.onreadystatechange = function stateChange() {
    if (engine.readyState == 4) {
        if (engine.status == 200 || engine.status == 201) { if(successHandler) successHandler(engine); }
        else { if(errorHandler) errorHandler(engine); }
    }
};
engine.open(verb.toUpperCase(), api_url, true);
// setRequestHeader() must be called AFTER open() !!
engine.setRequestHeader("Content-Type", "text/html; charset=utf-8");
engine.setRequestHeader('Accept', 'application/javascript');
engine.setRequestHeader('Cache-Control', 'no-cache');
engine.setRequestHeader('Pragma', 'no-cache');
engine.send(params.join("&amp;"));
</code></pre><p>};</p><p>[/source]</p><p>To use these JavaScript versions, just pass a couple of functions as parameters, and you&#8217;re done; they will be called in case of success or error, asynchronously.</p><p>Finally, the Cocoa / Objective-C wrapper (both synchronous and asynchronous, header and implementation files):</p><p>[source:c]
/*
Command-line example that uses this library:</p><h1>import <Foundation/Foundation.h></h1><p>int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool;
pool = [[NSAutoreleasePool alloc] init];</p><pre><code>AKResourceSubClass* resource;
resource = [[AKResourceSubClass alloc] init];
[resource get];
NSDictionary* plist = [resource getPropertyList];
// Do something with the results...
[pool drain];
return 0;
</code></pre><p>}
*/</p><h1>import <Foundation/Foundation.h></h1><p>@interface AKResource : NSObject {
NSMutableData* receivedData;</p><pre><code>NSString* mimeType;
NSString* server;
NSString* username;
NSString* password;
BOOL async;
</code></pre><p>}</p><p>-(id)init;
-(void)setServer:(NSString<em>)serverName;
-(void)setUsername:(NSString</em>)user
andPassword:(NSString<em>)pwd;
-(void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response;
-(void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data;
-(void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error;
-(void)connectionDidFinishLoading:(NSURLConnection *)connection;
-(void)sendRequestTo:(NSString</em>)urlString
usingVerb:(NSString<em>)verb
withParameters:(NSDictionary</em>)parameters;
-(void)setAsynchronous:(BOOL)asynchronously;
-(NSDictionary<em>)getPropertyList;
-(NSString</em>)getResponseText;</p><p>@end
[/source]</p><p>Now the implementation file:</p><p>[source:c]</p><h1>import &#8220;AKResource.h&#8221;</h1><p>@implementation AKResource</p><p>-(id)init
{
self = [super init];</p><pre><code>if(self)
{
    receivedData = [[NSMutableData alloc] init];
    mimeType = @"application/plist";
    server = @"localhost";
    username = @"";
    password = @"";
    async = NO;
}
return self;
</code></pre><p>}</p><p>-(void)setServer:(NSString*)serverName
{
server = serverName;
}</p><p>-(void)setUsername:(NSString<em>)user andPassword:(NSString</em>)pwd
{
username = user;
password = pwd;
}</p><p>-(void)sendRequestTo:(NSString<em>)resource
usingVerb:(NSString</em>)verb
withParameters:(NSDictionary<em>)parameters
{
NSURL</em> url = [NSURL URLWithString:[NSString
stringWithFormat:@"http://%@/%@", server, resource]];</p><pre><code>NSMutableDictionary* headers = [[NSMutableDictionary alloc] init];
[headers setValue:@"text/html; charset=utf-8"
    forKey:@"Content-Type"];
[headers setValue:mimeType forKey:@"Accept"];
[headers setValue:@"no-cache" forKey:@"Cache-Control"];
[headers setValue:@"no-cache" forKey:@"Pragma"];
NSMutableURLRequest* request;
request = [NSMutableURLRequest requestWithURL:url
            cachePolicy:NSURLRequestUseProtocolCachePolicy
            timeoutInterval:60.0];
[request setHTTPMethod:verb];
[request setAllHTTPHeaderFields:headers];
if (parameters)
{
    NSMutableString* params = [[NSMutableString alloc] init];
    for (id key in parameters)
    {
        [params appendFormat:@"%@=%@&amp;",
            [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
            [[parameters objectForKey:key]
                stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    }
    [params deleteCharactersInRange:NSMakeRange([params length] - 1, 1)];
    NSData* body = [params dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:body];
}
if (async)
{
    NSURLConnection* connection;
    connection = [[NSURLConnection alloc]  initWithRequest:request
                                            delegate:self
                                            startImmediately:YES];
    if (!connection)
    {
        NSLog(@"Could not open connection to resource");
    }
}
else
{
    NSURLResponse* response = [[NSURLResponse alloc] init];
    NSError* error = [[NSError alloc] init];
    NSData* data = [NSURLConnection
        sendSynchronousRequest:request
        returningResponse:&amp;response
        error:&amp;error];
    [receivedData setData:data];
}
</code></pre><p>}</p><p>-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLCredential *newCredential;
newCredential = [NSURLCredential credentialWithUser:username
password:password
persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential
forAuthenticationChallenge:challenge];
}</p><p>-(void)connection:(NSURLConnection <em>)connection
didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse</em> httpResponse;
httpResponse = (NSHTTPURLResponse<em>)response;
int statusCode = [httpResponse statusCode];
if (statusCode != 200)
{
NSMutableDictionary</em> info;
info = [NSMutableDictionary dictionaryWithObject:[response URL]
forKey:NSErrorFailingURLStringKey];
[info setObject:@"An error code different than 200 was received!"
forKey:NSLocalizedDescriptionKey];
NSError* error = [NSError errorWithDomain:@"API Wrapper"
code:statusCode
userInfo:info];
NSDictionary* errorData = [NSDictionary
dictionaryWithObject:error
forKey:@"error"];</p><pre><code>    [[NSNotificationCenter defaultCenter]
        postNotificationName:@"ConnectionDidFailWithStatusCodeNotOK"
        object:self
        userInfo:errorData];
}
[receivedData setLength:0];
</code></pre><p>}</p><p>-(void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}</p><p>-(void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
[connection release];</p><pre><code>NSDictionary* errorData = [NSDictionary
                            dictionaryWithObject:error
                            forKey:@"error"];
[[NSNotificationCenter defaultCenter]
    postNotificationName:@"ConnectionDidFailWithError"
    object:self
    userInfo:errorData];
NSLog(@"Connection failed! Error - %@ %@",
      [error localizedDescription],
      [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
</code></pre><p>}</p><p>-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[[NSNotificationCenter defaultCenter]
postNotificationName:@&#8221;ConnectionDidFinishLoading&#8221;
object:self];
[connection release];
}</p><p>-(void)setAsynchronous:(BOOL)asynchronously
{
async = asynchronously;
}</p><p>-(NSDictionary<em>)getPropertyList
{
NSString</em> errorStr = nil;
NSDictionary* propertyList;
NSPropertyListFormat format;</p><pre><code>propertyList = [NSPropertyListSerialization
                propertyListFromData:receivedData
                mutabilityOption: NSPropertyListImmutable
                format: &amp;format
                errorDescription: &amp;errorStr];
return propertyList;
</code></pre><p>}</p><p>-(NSString*)getResponseText
{
return [[NSString alloc]
initWithData:receivedData
encoding:NSUTF8StringEncoding];
}</p><p>@end
[/source]</p><p>Rather verbose this last one huh? Objective-C has a distinctive characteristic, inherited from Smalltalk (I suppose): methods with named parameters, like &#8220;stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding&#8221; (decidedly, one of the longest method calls ever :) The good thing is that the code reads like a book. This is why I like this language, as well as Ruby: you can read code in these languages very easily.</p><p>Another nice aspect of this Objective-C wrapper is that if you have an API that can return <a
href="http://en.wikipedia.org/wiki/Property_list">&#8220;Property Lists&#8221;</a> (like the one I&#8217;ve been working on lately), you can send object graphs serialized in XML that are completely Cocoa-compatible. That&#8217;s what the getPropertyList method does: client code can deal with standard NSDictionary instances, no need to do anything else!</p><p>Of course these are not the only ways to do this, but so far these wrappers have helped me a lot. Don&#8217;t hesitate to leave your comments below! And most important, have fun! As always, use this code at your own risk.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/playing-with-http-libraries/feed/</wfw:commentRss> <slash:comments>37</slash:comments> </item> </channel> </rss>
