<?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; Cocoa</title> <atom:link href="http://kosmaczewski.net/category/cocoa/feed/" rel="self" type="application/rss+xml" /><link>http://kosmaczewski.net</link> <description></description> <lastBuildDate>Wed, 08 Feb 2012 08:51:50 +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>iPhone and Mac OS X Developer Conference Roundup</title><link>http://akosma.com/2009/10/01/iphone-and-mac-os-x-developer-conference-roundup/</link> <comments>http://akosma.com/2009/10/01/iphone-and-mac-os-x-developer-conference-roundup/#comments</comments> <pubDate>Thu, 01 Oct 2009 15:36:10 +0000</pubDate> <dc:creator>akosma software</dc:creator> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[Opinion]]></category> <category><![CDATA[conference]]></category> <category><![CDATA[Mac OS X]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[WWDC]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1948</guid> <description><![CDATA[Here&#8217;s a quick review of the most important iPhone and Mac OS X developer conferences I&#8217;ve found on the web (in no particular order). Definitely, there&#8217;s no shortage of conferences when you need information about the latest Cocoa, Mac OS &#8230; <a
href="http://akosma.com/2009/10/01/iphone-and-mac-os-x-developer-conference-roundup/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Here&#8217;s a quick review of the most important iPhone and Mac OS X developer conferences I&#8217;ve found on the web (in no particular order). Definitely, there&#8217;s no shortage of conferences when you need information about the latest Cocoa, Mac OS X and iPhone technologies; check this out!</p><ul><li>Apple&#8217;s <a
href="http://developer.apple.com/wwdc/">Worldwide Developer Conference</a> or WWDC, held every year in San Francisco, CA (USA), usually around June, and featuring presentations from Apple employees; if you&#8217;ve never been to one, believe me, you should;</li><li>Voices That Matter <a
href="http://www.voicesthatmatter.com/iPhone2009/">iPhone Developer Conference</a> to be held in Boston, MA (USA) next October 17th and 18th, with (among others) Erica Sadun, Aaron Hillegass, Stephen Kochan and Marcus Zarra;</li><li><a
href="http://www.nsconference.com/">NSConference</a>, to be held from January 31st to February 3rd next year near Reading (UK), and from February 21st to February 24th in the Georgia Tech Institute, GA (USA), featuring (among others) Matt Gemmell, Marcus Zarra and Aaron Hillegass;</li><li>The <a
href="http://www.360idev.com/">360|iDev conference</a> that just finished in Denver, CO (USA), which featured (among many others) Bill Dudney, Brent Simmons, and Marcus Zarra (definitely, Marcus Zarra is everywhere!);</li><li>The <a
href="http://www.iphonedevsummit.com/">iPhone Developer Summit</a> in Santa Clara, CA (USA) next November 3rd;</li><li>The <a
href="http://www.igsummit.com/">iGames Summit</a>, a conference targeted to iPhone game developers, held last March in San Francisco, CA (USA), featuring (among many others) Neil Young (from ngmoco), Andrew Lacy (from Tapulous) and Mike Mettler (from AdMob);</li><li>The <a
href="http://macoun.de/">Macoun Entwicklerkonferenz</a> which happened last September 26th in Frankfurt (Germany);</li><li>The <a
href="http://iphonedevcon.de/">iPhone developer conference</a> in Köln (Germany), in December 1st and 2nd;</li><li>And finally, the <a
href="http://iphonedevday.com/">JAOO iPhone Dev Day</a> in Zürich (Switzerland) next October 8th, featuring Raven Zachary, Alex Cone and&#8230; many others ;)</li></ul><p>Also noteworthy, but not so much about software development I think, is the <a
href="http://www.mobileenterprise09.com/">Mobile Enterprise Conference</a> in Amsterdam (Netherlands) on November 3rd, which has a couple of tracks about the iPhone in enterprise.</p><p>Feel free to add links to other similar events elsewhere in the world!</p><p><strong>Update, 2009-10-02</strong>: Here&#8217;s the link to Jonathan &#8216;Wolf&#8217; Rentzsch&#8217;s <a
href="http://rentzsch.com/c4">C4 Independent Developers Conference</a>.</p><p><strong>Update, 2009-10-03</strong>: The <a
href="http://www.oredev.org/">Øredev 2009 Developer Conference</a> in Malmö (Sweden) next November has iPhone / Mobile tracks too. And so will the <a
href="http://scandevconf.se/">Scandinavian Developer Conference 2010</a> in Göteborg (also in Sweden).</p> ]]></content:encoded> <wfw:commentRss>http://akosma.com/2009/10/01/iphone-and-mac-os-x-developer-conference-roundup/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Best WWDC Ever</title><link>http://kosmaczewski.net/best-wwdc-ever/</link> <comments>http://kosmaczewski.net/best-wwdc-ever/#comments</comments> <pubDate>Sat, 13 Jun 2009 00:20:23 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Cocoa]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[Opinion]]></category> <category><![CDATA[conference]]></category> <category><![CDATA[thanks]]></category> <category><![CDATA[Twitter]]></category> <category><![CDATA[WWDC]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1552</guid> <description><![CDATA[&#8230; and WWDC 2009 is finally over. This year&#8217;s event has been nothing short of amazing; maybe because not only the technologies presented blew my mind, but also because I met and spent some time with incredible guys, and getting &#8230; <a
href="http://kosmaczewski.net/best-wwdc-ever/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>&#8230; and WWDC 2009 is finally over.</p><p>This year&#8217;s event has been nothing short of amazing; maybe because not only the technologies presented blew my mind, but also because I met and spent some time with incredible guys, and getting in touch with the right people changes everything. So, to all of you, many thanks: <a
href="http://twitter.com/cigumo">@cigumo</a>, <a
href="http://twitter.com/dlpasco">@dlpasco</a>, <a
href="http://twitter.com/sophiestication">@sophiestication</a>, <a
href="http://twitter.com/davemark">@davemark</a>, <a
href="http://twitter.com/jeff_lamarche">@jeff_lamarche</a>, <a
href="http://twitter.com/markuspalmanto">@markuspalmanto</a>, <a
href="http://twitter.com/serpah">@serpah</a>, <a
href="http://twitter.com/raminf">@raminf</a>, <a
href="http://twitter.com/geraudch">@geraudch</a>, <a
href="http://twitter.com/ayasin">@ayasin</a>, <a
href="http://twitter.com/octopus_prime">@octopus_prime</a>, <a
href="http://twitter.com/pjay_">@pjay_</a>, <a
href="http://twitter.com/2009wwdc">@2009wwdc</a> and all the others, in and out of Twitter, like Julio from Guatemala, the guy from Adobe (met in the queue to the hotdogs in the beer bash of Yerba Buena gardens), Sandro (aka &#8220;The Crazy Swiss Guy&#8221; of the Stump the Experts session), etc, etc, etc&#8230; with whom we&#8217;ve shared laughs, ideas, emotion, friendship and beers.</p><p>WWDC is an inspiring event: listening to the above guys, or the conferences from <a
href="http://www.smule.com/">Smule</a> or <a
href="http://blog.ngmoco.com/">ngmoco:)</a> talking about their companies, and how they grew up the past year, all of that makes me think about this new path I&#8217;m taking right now:</p><p><strong><a
href="http://akosma.com/">akosma software</a> is born.</strong> Expect a lot.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/best-wwdc-ever/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>NIBs or code? Why not both? Here&#8217;s nib2objc.</title><link>http://akosma.com/2009/03/17/nib2objc/</link> <comments>http://akosma.com/2009/03/17/nib2objc/#comments</comments> <pubDate>Tue, 17 Mar 2009 19:52:57 +0000</pubDate> <dc:creator>akosma software</dc:creator> <category><![CDATA[Cocoa]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[design]]></category> <category><![CDATA[git]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[project]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1459</guid> <description><![CDATA[(Somehow this project seems to me so simple, that I&#8217;m sure someone has done this before. Anyway). This is my feeble attempt to bring an answer to the eternal dichotomy between those arguing about the relative benefits of creating user &#8230; <a
href="http://akosma.com/2009/03/17/nib2objc/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>(Somehow this project seems to me so simple, that I&#8217;m sure someone has done this before. Anyway). This is my feeble attempt to bring an answer to the eternal dichotomy between those arguing about the relative benefits of creating user interfaces via Interface Builder or via pure Objective-C code: let me introduce <a
href="http://github.com/akosma/nib2objc/">nib2objc</a>.</p><p>Unbeknown to most of us, the <a
href="http://developer.apple.com/DOCUMENTATION/DARWIN/Reference/ManPages/man1/ibtool.1.html">ibtool</a> utility bundled with Interface Builder and Xcode allows us to inspect the contents of NIB files (or XIBs, for that matter) and get from them nice property lists XML streams, which I transform in NSDictionary instances, which I loop over and over util I get something that looks like this:</p><p>[source:c]
UIView *view6 = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 460.0)];
view6.frame = CGRectMake(0.0, 0.0, 320.0, 460.0);
view6.alpha = 1.000;
view6.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
view6.backgroundColor = [UIColor colorWithWhite:0.750 alpha:1.000];
view6.clearsContextBeforeDrawing = NO;
// &#8230;</p><p>UIButton *view9 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
view9.frame = CGRectMake(167.0, 65.0, 72.0, 37.0);
view9.adjustsImageWhenDisabled = YES;
view9.adjustsImageWhenHighlighted = YES;
view9.alpha = 1.000;
view9.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
view9.clearsContextBeforeDrawing = NO;
view9.clipsToBounds = NO;
view9.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
// &#8230;
[view9 setTitleShadowColor:[UIColor colorWithWhite:0.000 alpha:1.000] forState:UIControlStateSelected];</p><p>// &#8230;
[view6 addSubview:view9];
// &#8230;
[/source]</p><p>Using this tool, I can now use IB for design, and then generate the code for those designs, in case I prefer to use a code-only approach (usually for UITableViewCells, <a
href="/2009/01/28/10-iphone-memory-management-tips/">as I explained before</a>). For the moment it only works with UIKit classes, but I don&#8217;t think it might be a problem to extend it to AppKit classes as well.</p><p>I hope this project is useful to all of you! As usual, open source, public domain and on <a
href="http://github.com/akosma/nib2objc/">Github</a>.</p><p><strong>Update, 2009-04-09:</strong> This project has been <a
href="http://arstechnica.com/apple/guides/2009/04/iphone-dev-convert-xib-files-to-objective-c.ars">featured in an article in Ars Technica</a> by <a
href="http://ericasadun.com/">Erica Sadun</a>!</p> ]]></content:encoded> <wfw:commentRss>http://akosma.com/2009/03/17/nib2objc/feed/</wfw:commentRss> <slash:comments>7</slash:comments> </item> <item><title>That Twitterriffic editor</title><link>http://kosmaczewski.net/that-twitterriffic-editor/</link> <comments>http://kosmaczewski.net/that-twitterriffic-editor/#comments</comments> <pubDate>Fri, 27 Feb 2009 22:37:06 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Cocoa]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[git]]></category> <category><![CDATA[Twitter]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1428</guid> <description><![CDATA[They say imitation is the best form of flattery. Well, here&#8217;s another attempt at doing that, after my &#8220;attack&#8221; on the Facebook iPhone app (decidedly I&#8217;m on a somewhat copying mood lately). I use Twitterriffic a lot, both on the &#8230; <a
href="http://kosmaczewski.net/that-twitterriffic-editor/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p><img
src="http://kosmaczewski.net/wp-content/uploads/2009/02/twitterriffic-200x300.png" alt="" title="twitterriffic" width="200" height="300" class="alignnone size-medium wp-image-1424" align="left" hspace="10" />They say imitation is the best form of flattery. Well, here&#8217;s another attempt  at doing that, after <a
href="/2009/02/24/that-facebook-strip/">my &#8220;attack&#8221;</a> on the Facebook iPhone app (decidedly I&#8217;m on a somewhat copying mood lately).</p><p>I use <a
href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284540316&#038;mt=8">Twitterriffic</a> a lot, both on the iPhone and on my Mac, and particularly in the iPhone version, I&#8217;ve always liked the little editor for tweets. It grows and shrinks as you type, it appears and disappears following the keyboard, and it provides a standard toolbar with many useful buttons (Actually, I wish the Mac version would have a similar text entry box, which would grow bigger as I type; it&#8217;s probably the only complaint I have about it!)</p><p>Well, here&#8217;s my own attempt at doing something similar, and after 1 hour of work, <a
href="http://github.com/akosma/editorrific/tree/master">the result is published, ready for you to enjoy at Github</a>. As usual, no strings attached, pure public domain stuff, so use it and play with it as you wish.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/that-twitterriffic-editor/feed/</wfw:commentRss> <slash:comments>5</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>Objective-C REST Client Update</title><link>http://kosmaczewski.net/objective-c-rest-client-update/</link> <comments>http://kosmaczewski.net/objective-c-rest-client-update/#comments</comments> <pubDate>Mon, 19 Jan 2009 11:40:26 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Cocoa]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[HTTP]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[project]]></category> <category><![CDATA[REST]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1319</guid> <description><![CDATA[I&#8217;ve uploaded (yet another) update to the Objective-C REST client I&#8217;ve blogged about previously. This time I&#8217;ve scanned the code with the excellent LLVM/Clang Static Analyzer and fixed a couple of memory leaks here and there. I strongly recommend to &#8230; <a
href="http://kosmaczewski.net/objective-c-rest-client-update/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>I&#8217;ve uploaded (yet another) update to the <a
href="/projects/objective-c-rest-client/">Objective-C REST client</a> <a
href="/2008/10/18/rest-and-objective-c-again/">I&#8217;ve blogged about previously</a>. This time I&#8217;ve scanned the code with the excellent <a
href="http://clang.llvm.org/StaticAnalysis.html">LLVM/Clang Static Analyzer</a> and fixed a couple of memory leaks here and there. I strongly recommend to scan your own projects with this tool, it&#8217;s extremely simple to use:</p><ol><li>Install it somewhere in your PATH;</li><li><del
datetime="2009-01-19T14:55:18+00:00">Set your projects to use the Debug configuration when building from the command line (you can do that in the inspector for the project, in the &#8220;Configurations&#8221; tab);</del> (see Sebastien&#8217;s comment below ;)</li><li>Open Terminal.app and fire<pre>scan-build -k -V xcodebuild</pre>on the root of the Xcode project folder;</li><li>If there are any problems with your code, you&#8217;ll have your web browser pop up with the list of problems, their description in annotated code format, and even a link to open the file right away.</li></ol><p><span
id="more-1319"></span> I have also fixed another problem with the code, which was preventing POST data to be properly sent to the server with the previous version. You might have encountered this problem, and here is the solution: instead of using NSString&#8217;s stringByAddingPercentEscapesUsingEncoding: method, use CoreFoundation&#8217;s CFURLCreateStringByAddingPercentEscapes() function. This means that this code:</p><p>[source:C:firstline(68)]
[params appendFormat:@"%@=%@&amp;", [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[[parameters objectForKey:key] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[/source]</p><p>became this:</p><p>[source:C:firstline(68)]
NSString *encodedKey = [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
CFStringRef value = (CFStringRef)[[parameters objectForKey:key] copy];
// Escape even the &#8220;reserved&#8221; characters for URLs
// as defined in http://www.ietf.org/rfc/rfc2396.txt
CFStringRef encodedValue = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
value,
NULL,
(CFStringRef)@&#8221;;/?:@&amp;=+$,&#8221;,
kCFStringEncodingUTF8);
[params appendFormat:@"%@=%@&amp;", encodedKey, encodedValue];
CFRelease(value);
CFRelease(encodedValue);
[/source]</p><p>Now any text sequence, including any &#8220;legal&#8221; URL character (as explained in the RFC), will be encoded properly and sent to the server as required.</p><p>Cocoa only provides a thin layer over many of CoreFoundation functions and types; it does not expose completely all the functionality &#8220;below&#8221;, and that&#8217;s why sometimes you must dig a bit deeper and call CoreFoundation code to certain operations, like using the Address Book data, or playing sounds in your iPhone applications. The good thing, as always, is that CoreFoundation types are &#8220;toll free&#8221; bridged, which means that you can safely cast a CFStringRef into an NSString pointer without any overhead.</p><p>Chris Adamson explained this as an <a
href="http://blogs.oreilly.com/iphone/2009/01/opt-in-complexity.html">&#8220;Opt-in Complexity&#8221; pattern</a>, in an article in the <a
href="http://blogs.oreilly.com/iphone/blog/">Inside iPhone blog</a> last week:</p><blockquote>Need time zone awareness? NSTimeZone is your friend. Need to know every time zone that the device supports? Get to know CFTimeZoneCopyKnownNames(). Again, a niche-ier feature lives down at the Core Foundation level, and isn&#8217;t wrapped by an equivalent call in Foundation, though it&#8217;s easy enough to switch to procedural C and make the one-off lower-level call.</blockquote> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/objective-c-rest-client-update/feed/</wfw:commentRss> <slash:comments>7</slash:comments> </item> <item><title>iPhone Conference 2008: a bit of magic!</title><link>http://kosmaczewski.net/iphone-conference-2008-a-bit-of-magic/</link> <comments>http://kosmaczewski.net/iphone-conference-2008-a-bit-of-magic/#comments</comments> <pubDate>Mon, 03 Nov 2008 17:00:31 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa]]></category> <category><![CDATA[Opinion]]></category> <category><![CDATA[Papers]]></category> <category><![CDATA[Technology]]></category> <category><![CDATA[conference]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[Switzerland]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1264</guid> <description><![CDATA[This is the talk I gave last Friday during the first edition of the iPhone Conference 2008! I hope you&#8217;ll enjoy it as much as I enjoyed giving it :)]]></description> <content:encoded><![CDATA[<p>This is the talk I gave last Friday during the first edition of the iPhone Conference 2008! I hope you&#8217;ll enjoy it as much as I enjoyed giving it :)</p><p><object
width="400" height="225"><param
name="allowfullscreen" value="true" /><param
name="allowscriptaccess" value="always" /><param
name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=2126237&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" /> <embed
src="http://vimeo.com/moogaloop.swf?clip_id=2126237&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true"
allowscriptaccess="always" width="400" height="225"> </embed> </object></p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/iphone-conference-2008-a-bit-of-magic/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>REST and Objective-C, again</title><link>http://kosmaczewski.net/rest-and-objective-c-again/</link> <comments>http://kosmaczewski.net/rest-and-objective-c-again/#comments</comments> <pubDate>Sat, 18 Oct 2008 17:20:21 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Cocoa]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[project]]></category> <category><![CDATA[REST]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1263</guid> <description><![CDATA[I&#8217;ve just uploaded some code derived from the Objective-C wrapper I&#8217;ve shown in this post. You can find it in the &#8220;Projects&#8221; section, as usual and it&#8217;s simply a wrapper around the URL loading system of Cocoa, both for Macs &#8230; <a
href="http://kosmaczewski.net/rest-and-objective-c-again/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>I&#8217;ve just uploaded some code derived from the Objective-C wrapper I&#8217;ve shown <a
href="/2008/03/26/playing-with-http-libraries/">in this post</a>. You can find it <a
href="/projects/objective-c-rest-client/">in the &#8220;Projects&#8221; section, as usual</a> and it&#8217;s simply a wrapper around the URL loading system of Cocoa, both for Macs and iPhones, providing a custom delegate protocol, so that you can handle the events raised by the wrapper:</p><p>[source:C::firstline(13)]
@protocol WrapperDelegate</p><p>@required
- (void)wrapper:(Wrapper *)wrapper
didRetrieveData:(NSData *)data;</p><p>@optional
- (void)wrapperHasBadCredentials:(Wrapper *)wrapper;
- (void)wrapper:(Wrapper *)wrapper
didCreateResourceAtURL:(NSString *)url;
- (void)wrapper:(Wrapper *)wrapper
didFailWithError:(NSError *)error;
- (void)wrapper:(Wrapper *)wrapper
didReceiveStatusCode:(int)statusCode;</p><p>@end
[/source]</p><p>The sample project, available in the <a
href="/wp-content/uploads/2008/10/restwrapper.zip">zip file</a>, shows how a simple Cocoa controller can interact with the Wrapper class as required. Enjoy!</p><p><strong>Update, 2008-10-26:</strong> After a bug report from <a
href="http://www.pomcast.net/">StuFF mc</a> I&#8217;ve updated the code for a better support of POST and PUT requests, and also added a sample PHP file for a quick test of the functionalities.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/rest-and-objective-c-again/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>The beauty of Cocoa</title><link>http://kosmaczewski.net/the-beauty-of-cocoa/</link> <comments>http://kosmaczewski.net/the-beauty-of-cocoa/#comments</comments> <pubDate>Tue, 08 Jul 2008 16:46:44 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[Humour]]></category> <category><![CDATA[Opinion]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[design]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/?p=1229</guid> <description><![CDATA[(Highly geeky post ahead. You&#8217;ve been warned!) I have found the very message that summarizes the beauty of Cocoa in a single word; see by yourselves, hereunder in line 47: [source:c] import // The interface of a person @interface Person &#8230; <a
href="http://kosmaczewski.net/the-beauty-of-cocoa/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>(Highly geeky post ahead. You&#8217;ve been warned!)</p><p>I have found the very message that summarizes the beauty of Cocoa in a single word; see by yourselves, hereunder in line 47:</p><p>[source:c]</p><h1>import <Foundation/Foundation.h></h1><p>// The interface of a person
@interface Person : NSObject {
NSString* firstName;
NSString* lastName;
int age;
}
@end</p><p>// The implementation of the Person
@implementation Person
-(id)init {
if (self = [super init]) {
firstName = @&#8221;";
lastName = @&#8221;";
age = 0;
}
return self;
}</p><p>-(void)dealloc {
[firstName release];
[lastName release];
[super dealloc];
}</p><p>-(NSString*)description {
return [[NSString alloc]
initWithFormat:@&#8221;Name: %@ %@, %d years old&#8221;,
firstName, lastName, age];
}
@end</p><p>// Some code using the Person class
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];</p><pre><code>NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
[dict setObject:@"Teto" forKey:@"firstName"];
[dict setObject:@"Rodriguez" forKey:@"lastName"];
[dict setObject:[[NSNumber alloc] initWithInt:34] forKey:@"age"];
Person* person = [[[Person alloc] init] autorelease];
// The beauty of Cocoa can be resumed to this very line:
[person setValuesForKeysWithDictionary:dict];
// Now sit back and relax:
NSLog([person description]);
[pool drain];
return 0;
</code></pre><p>}
[/source]</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/the-beauty-of-cocoa/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Screen Savers for the Mac using Flash</title><link>http://kosmaczewski.net/screen-savers-for-the-mac-using-flash/</link> <comments>http://kosmaczewski.net/screen-savers-for-the-mac-using-flash/#comments</comments> <pubDate>Tue, 18 Mar 2008 21:30:15 +0000</pubDate> <dc:creator>Adrian</dc:creator> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa]]></category> <category><![CDATA[How to?]]></category> <category><![CDATA[Open Source]]></category> <category><![CDATA[project]]></category> <guid
isPermaLink="false">http://kosmaczewski.net/2008/03/18/screen-savers-for-the-mac-using-flash/</guid> <description><![CDATA[This is an evening project that turned out to be really cool. Let&#8217;s say that you&#8217;re a Macromedia Flash designer, and your clients ask you to bundle your nice Flash movie as a screen saver. What to do? For Windows &#8230; <a
href="http://kosmaczewski.net/screen-savers-for-the-mac-using-flash/">Continue reading <span
class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>This is an evening project that turned out to be really cool. Let&#8217;s say that you&#8217;re a Macromedia Flash designer, and your clients ask you to bundle your nice Flash movie as a screen saver. What to do? For Windows there are free utilities to convert a SWF into a screen saver, but not for the Mac &#8211; and the first commercial one costs around USD 200!</p><p>I propose here a simple solution for this problem:</p><ol><li>Using Xcode, you can create screen savers (basically, Cocoa apps).</li><li>Cocoa applications can host a WebKit component (basically, Safari).</li><li>Safari can show local HTML pages (basically, &#8220;file:///&#8221; stuff).</li><li>And HTML pages can show Flash movies (basically, &lt;OBJECT&gt; and &lt;EMBED&gt;)</li></ol><p>The idea, then, is to bundle your own page, with your own movie, inside the screen saver bundle, and show the Flash movie this way. Easy said, easy done.</p><p>It all goes nice until&#8230; you try this solution :) The problem is, Flash movies loaded from &#8220;file:///&#8221; URLs are blocked by the built-in security mechanisms of Adobe&#8230; and you have to find a workaround for that. Mine was to follow the <a
href="http://kb.adobe.com/selfservice/viewContent.do?externalId=1165eb90">instructions</a> on how to bypass the Flash security mechanism, and then create an installer package that will do what&#8217;s needed for you to enjoy the screen saver.</p><p>You can get both the project and the installer package in my <a
href="/projects/flash-screen-saver/">projects section</a>. I&#8217;ve tested the installer in three different machines, and it worked, so I hope it&#8217;ll work for you too :) Enjoy! As always, try this at your own risk. Murphy says that things can go wrong, so watch out.</p> ]]></content:encoded> <wfw:commentRss>http://kosmaczewski.net/screen-savers-for-the-mac-using-flash/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss>
