<?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>toxicsoftware.com</title> <atom:link href="http://toxicsoftware.com/feed/" rel="self" type="application/rss+xml" /><link>http://toxicsoftware.com</link> <description>RANDOMIZE USR 0</description> <lastBuildDate>Thu, 22 Dec 2011 03:35:22 +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>NSLunch</title><link>http://toxicsoftware.com/nslunch/</link> <comments>http://toxicsoftware.com/nslunch/#comments</comments> <pubDate>Wed, 21 Dec 2011 18:13:13 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=569</guid> <description><![CDATA[I haven&#8217;t interacted enough with my fellow Cocoa developers (outside of work that is) since moving to the Bay Area. So I&#8217;ve started NSLunch (yes, totally original name). A regular lunchtime meet up with your fellow San Francisco area Cocoa &#8230; <a href="http://toxicsoftware.com/nslunch/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>I haven&#8217;t interacted enough with my fellow Cocoa developers (outside of work that is) since moving to the Bay Area. So I&#8217;ve started <a href="http://bit.ly/NSLunch">NSLunch</a> (yes, totally original name). A regular lunchtime meet up with your fellow San Francisco area Cocoa developers. We&#8217;ll see if it&#8217;s a success or if I end up eating lunch alone.</p> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/nslunch/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>UIStoryboard Issues</title><link>http://toxicsoftware.com/uistoryboard-issues/</link> <comments>http://toxicsoftware.com/uistoryboard-issues/#comments</comments> <pubDate>Tue, 13 Dec 2011 22:39:52 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=548</guid> <description><![CDATA[Background In August I joined a new start-up as lead (and only) iOS Developer. I managed to convince the founders that targeting iOS 5 was a good idea and as such I&#8217;ve embraced a lot of new iOS 5 only &#8230; <a href="http://toxicsoftware.com/uistoryboard-issues/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<h2>Background</h2><p>In August I joined a new start-up as lead (and only) iOS Developer. I managed to convince the founders that targeting iOS 5 was a good idea and as such I&#8217;ve embraced a lot of new iOS 5 only technologies in the app including <a href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIStoryboard_Class/Reference/Reference.html">UIStoryboard</a>.</p><p>After a few months of development with UIStoryboard I&#8217;ve decided that the technology just isn&#8217;t mature enough to be used in a complex iOS application and have now replaced all* UIStoryboard with traditional NIBs.</p><p>(* I have left in standalone storyboards for parts of the app heavily in flux, but will be replacing this usage with NIBs in the future).</p><h2>Storyboard Editor</h2><p>The storyboard editor in Xcode 4 combines all the problems of the Interface editor (e.g. broken keyboard navigation, somewhat broken selection semantics, amnesia for useful settings like &#8220;show bounds&#8221;, etc) with the inability to edit interfaces on a small (17&#8243;) screen. Once the storyboard expands beyond a half dozen or so view controllers the storyboard editor becomes very hard to use, with constant panning and zooming to find the view controller you want to edit.</p><p>One problem with storyboards with lots of view controllers (my app had around 30 view controllers in a single storyboard) is that everything looks the same. Visually a lot of view controllers end up being some kind of variation on a white rectangle (esp. when zoomed out). I found myself tending to rely on a knowledge of the storyboard &#8220;geography&#8221; to find the view controller I was looking for. And even familiar with the layout of the view controllers I still found myself hunting and pecking for the right view controller (&#8220;oh no wait, that&#8217;s the parent UINavigationController, I must want the child instead&#8221;).</p><p>A somewhat related but inverse problem is that it seems to be impossible to use UITableView static cells &amp; prototype cells outside of a storyboard. This seems strange. Being forced to use storyboards if you want to use this very useful feature is serious problem. I have to assume this is an oversight.</p><h2>&#8220;Spaghetti&#8221; Segues</h2><p>With moderately complex storyboards the view controllers and their segues begin to resemble spaghetti. I found this especially common when I had multiple &#8220;detail&#8221; view controllers that could be accessible from each other (think of a twitter app &#8211; you can view people in a people table and tweets in a tweet table, and drill down in people/tweet detail screens. But you can also access a person detail screen from an individual tweet detail screen and vice versa). I wonder if the master view controller source list (presented on the left of storyboard editor) should not be the primary view for the editor, with the ability to focus on one view controller at a time?</p><h2>Segue Identifiers</h2><p>It becomes readily apparent that the segue identifier field (settable in the editor) is the best way to differentiate between segues in large prepareForSegue: implementations (see more on this later). It would be very handy if Xcode 4 supported a &#8220;warn on missing segue identifier&#8221; option when storyboards are &#8220;compiled&#8221; into individual NIBs. (feature request)</p><h2>View Controller Identifiers</h2><p>It is possible to assign view controllers in a storyboard an identifier. Unfortunately this identifier property is not exposed in the UIViewController class. This makes it very hard to perform safe introspection of the view controller hierarchy at runtime. It would be really nice if identifier was exposed for view controllers as well as for segues. (Feature request)</p><h2>Push-only Segues</h2><p>Segues are by default &#8220;additive&#8221; only: you can push a view controller onto the navigation stack or present it modally but it isn&#8217;t possible to perform other common navigation tasks without resorting to custom segues. For instance you can&#8217;t jump to a view controller further down the navigation stack or change the tab of a tab bar. And the ability to jump to an arbitrary view controller in the view controller hierarchy (without a push) doesn&#8217;t seem possible at all.</p><p>Custom segues do allow you to do some of this. In fact I have written a custom segue to jump to a different tab in UITabBarController, but it was rather hacky code to get around the fact that the segue automatically created a new destination view controller for me.</p><p>I think it would be handy if these, more complex segues, were built into the UIStoryboard system by default.</p><h2>Misuse sender field.</h2><p>A common iOS design pattern is to create a new detail view controller, populate it with the relevant detail and then present it (either push onto the navigation stack or present modally). Generally I&#8217;d accomplish this with a custom &#8220;initWithFoo:&#8221; method on the detail view controller.</p><pre><code>CUser *theUser = [self.fetchedResultsController objectAtIndexPath:indexPath];
CUserProfileViewController *theViewController = [[CUserProfileViewController alloc] initWithUser:theUser];
UINavigationController *theNavigationController = [[UINavigationController alloc] initWithRootController:theViewController];
[self presentViewController:theNavigationController animated:YES completion:NULL];
</code></pre><p>With storyboarding there&#8217;s no clear way to pass data to a detail view controller. The best I could come up with was by abusing the sender parameter to pass the data the detail view controller needs, e.g.:</p><pre><code>CUser *theUser = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self performSegueWithIdentifier:@"ID_USER_DETAIL" sender:theUser];
</code></pre><p>The performWithSegue: method would then take the data and hand it to the already created destination view controller:</p><pre><code>- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
    if ([segue.identifier isEqualToString:@"ID_USER_DETAIL"])
        {
        UINavigationController *theNavigationController = AssertCast_(UINavigationController, segue.destinationViewController);
        CUserProfileViewController *theViewController = AssertCast_(CUserProfileViewController, theNavigationController.topViewController);
        theViewController.user = sender;
        }
    }
</code></pre><p>(Note I use my <a href="http://github.com/TouchCode/TouchFoundation/blob/master/Source/Asserts.h">AssertCast_</a> macro to make sure my assumptions about the view hierarchy are correct, I&#8217;ve been bitten too many times in the past by bad view controller hierarchy assumptions to not be paranoid here)</p><p>Not only is this a lot of code and complexity to replace something that was rather simple before, it seems to be an abuse of the &#8220;sender&#8221; parameter. Sender should really be (at least according to tradition) the button or the table cell or the map annotation, etc that triggered the segue and not the data the destination view controller needs to configure itself.</p><p>I tried to build my own performSegueWithIdentifier:sender:userInfo: and prepareForSegue:sender:userInfo: methods in a UIViewController category but it was clear it was going to have to do some nasty things (like define a prepareForSegue:sender: in the category in question) and I decided it was a no-go.</p><p>Perhaps I&#8217;m missing something here and there is a better way to accomplish this.</p><h2>Bloated prepareForSegue:</h2><p>My root view controller has become a source view controller for lot of segues and therefore its prepareForSegue: has become a stupidly large method filled with a lot of &#8220;if (segue.identifier isEqualToString:@&#8221;&#8230;&#8221;)&#8221; statements in a row. I don&#8217;t like this. I much preferred the way the same code was distributed to many view controllers instead.</p><p>I find this problem causes the code to become more brittle and less flexible. If I change the view controller hierarchy I need to find the relevant block of code in the source view controller and move it to the new view controller. Previously I didn&#8217;t have to do this at all. This totally eliminates the flexibility that storyboards can provide.</p><h2>No user defined relationships</h2><p>This was really the nail in coffin for storyboards for me.</p><p>I needed to create a new container view controller type that could flip between multiple child view controllers (rather like a UITabBarController but with different UI and animation). I implemented the view controller with a child &#8220;viewControllers&#8221; property and got the transitions and UI working and then realised that I couldn&#8217;t wire it up in a UIStoryboard successfully. I quickly realised that only UINavigationController and UITabBarController could have non-segue relationships to other view controllers (*). This basically made it impossible to use one large storyboard and would need to use traditional techniques (static view controller instantiation in this case) and break my single monolithic storyboards up into smaller storyboards that I could load root view controllers from as needed. Unfortunately because of the spaghetti problem I discussed previously this was going to be ugly.</p><p>At this point, combined with the other problems and issues I&#8217;d encountered up to now I decided to rip out my storyboard and replace it with the traditional one (or more) NIB per view controller.</p><h2>No code size benefits</h2><p>I spent almost a day replacing my storyboard (and related code) with NIBs (I am sure I have introduced new bugs into the app in the process that will take further time to find and fix). In doing so I actually reduced the line count by about 400 lines of code. It&#8217;s pretty clear that storyboards wont reduce the total of number of lines code in the app and due to the problems with prepareForSegue: discussed previously I don&#8217;t think storyboards will allow you to iterate designs more quickly than using NIBs.</p><h2>Is this my fault?</h2><p>So I&#8217;m left wondering if this could my fault, that I&#8217;m missing something or just don&#8217;t understand how I should be using storyboards. I don&#8217;t think so. I do think that I could learn to stop worrying about the sender/userInfo issue and perhaps I could work out a smart way to solve the prepareForSegue: bloat problem. But really, I don&#8217;t have the time for this, I need to be able to implement UI in a speedy manner without having to solve the &#8220;how do I make this work with UIStoryboards&#8221; problem.</p><h2>Summary</h2><p>I do think the UIStoryboard technology has a lot of potential but as I&#8217;ve discussed there are some rather severe issues with the current implementation that make it burdensome to use. That said I look forward to further iterations of the technology. Also if anyone has worked around these problems or think I&#8217;m doing it wrong please let me know.</p> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/uistoryboard-issues/feed/</wfw:commentRss> <slash:comments>16</slash:comments> </item> <item><title>Calling a Turd a Turd</title><link>http://toxicsoftware.com/calling-a-turd-a-turd/</link> <comments>http://toxicsoftware.com/calling-a-turd-a-turd/#comments</comments> <pubDate>Sun, 05 Jun 2011 17:42:18 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category> <category><![CDATA[criticism]]></category> <category><![CDATA[Development]]></category> <category><![CDATA[rant]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=526</guid> <description><![CDATA[Apparently my previous post is getting called out as &#8220;defensive&#8221; on the MacIndie blog. Well, again I assume it&#8217;s my post because the author so far hasn&#8217;t bothered to mention my post directly. Oh well. We&#8217;ll read between the lines &#8230; <a href="http://toxicsoftware.com/calling-a-turd-a-turd/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Apparently my previous post is getting called out as &#8220;defensive&#8221; on the <a href="http://macindie.com/2011/06/when-small-platforms-get-big-big-egos-need-to-get-small">MacIndie blog</a>. Well, again I assume it&#8217;s my post because the author so far hasn&#8217;t bothered to mention my post directly. Oh well. We&#8217;ll read between the lines and assume the author is targeting me. I&#8217;m not really worried if the post came over as defensive or not &#8211; it was merely stating why I believe that criticising and being open to criticism is a good thing.</p><p>I think the author is going along with Marcus&#8217; original point: in that it is the almost solely senior members of the community who were critical. This is ignoring all the criticism from folks like <a href="http://www.google.com/webhp?sourceid=chrome-instant&amp;ie=UTF-8&amp;ion=1&amp;nord=1#sclient=psy&amp;hl=en&amp;safe=off&amp;nord=1&amp;site=webhp&amp;source=hp&amp;q=site%3Adaringfireball.net%20The%20Daily&amp;aq=&amp;aqi=&amp;aql=&amp;oq=&amp;pbx=1&amp;fp=bb00a8cd1aea9d79&amp;ion=1&amp;ion=1&amp;bav=on.2,or.r_gc.r_pw.&amp;fp=bb00a8cd1aea9d79&amp;biw=1599&amp;bih=849&amp;ion=1">John Gruber</a>, <a href="http://www.subtraction.com/2011/04/06/guessing-at-numbers-for-the-daily">Khoi Vinh</a>, <a href="http://www.pcmag.com/article2/0,2817,2383171,00.asp">PC Mag</a> (<em>eww</em>), <a href="http://blogs.telegraph.co.uk/technology/shanerichmond/100006286/the-daily-ipad-app-review-a-complete-failure-of-imagination/">The Daily Telegraph</a> (double <em>eww</em>) and even the App reviews themselves (which as all good developers know &#8211; should be utterly ignored out of hand, because the peons know nothing!).</p><p>So this shows that it wasn&#8217;t just the old &#8220;grey beard&#8221; section of the Cocoa dev community(tm) &#8211; it was pretty much everybody. The app was wildly slammed by everyone because <em>everyone</em> saw it. It probably had the largest launch of any iOS app &#8211; and everyone saw it to be unpolished, slow, buggy and at the end of the day owned by a psychopath who makes Bond villains look huggable. In comparison the criticism from the old timers was relatively small (and if I recall correctly, tame).</p><p>Anyone parroting the &#8220;grey beard&#8221; line is either forgetting the mainstream criticism or is incapable of critical thinking.</p><p>I&#8217;m also a little bit confused because, no one officially knew who worked on the The Daily (although I&#8217;d say it was moderately common knowledge a few days after the launch). How can the community be accused of turning on one of its own if we had no clue who worked on the app? As far as we knew Murdoch probably outsourced it to indentured iOS child programmers in the jungles of Peru (no offense to real Peruvian child slave programmers &#8211; I&#8217;m sure you do great work).</p><p>A quick thought experiment: let&#8217;s say you were the client paying for the contractors (and sub-contractors) who worked on The Daily. Would you personally have been happy with the state it was in when it was released? I wouldn&#8217;t have been. I would have pushed as much as possible to move the deadline so that the blatant problems could be fixed. The fact that it was released anyway means to me, as is often the case with software, that making the deadline trumped the product quality.</p><p>I&#8217;d be really surprised if anyone was happy with the quality of the app when it was released (the same can almost always be said for any software release). So should we shut up when something is released with great fanfare and yet it, well quite frankly, isn&#8217;t very good? These hypothetical kids in Peru have it shit already, they&#8217;re working for the anti-christ as it is. Do they really need all these old timers they look up to and respect shitting on something they&#8217;ve poured their time and energy into?</p><p>The truth is children didn&#8217;t write the app. Grown adults did, adults who should expect and desire criticism from their peers. Not wanting or accepting criticism means you just want false platitudes. You don&#8217;t have to go too far to find them on the internet. Yes, writing software is hard work, we get it — but we all do it. Working as a sub-contractor to the anti-christ sounds like absolutely fucking miserable work, we get that too — but if you&#8217;ve got the stomach for it — good for you. But just because something is hard, or unpleasant to do — doesn&#8217;t mean that the end result doesn&#8217;t deserve criticism if it just isn&#8217;t very good.</p><p>That doesn&#8217;t diminish the fact that criticism is hard to take. It is, I&#8217;m personally awful at taking criticism. And developer egos are very fragile things and easily crushed. Having them crushed by your peers is certainly harder still. But without strong criticism, you end up applauding mediocrity. Fuck that. Give me a snarky bastard developer who tells me what I&#8217;m doing is crap. I&#8217;d take that any day over someone who tells me every single thing I do is wonderful.</p><p>I&#8217;ll end this post with words from Winston Churchill. who was much better at crafting them than I could ever hope to be:</p><blockquote><p>&#8220;Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things.&#8221;</p></blockquote> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/calling-a-turd-a-turd/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>90% of Everything is Crap</title><link>http://toxicsoftware.com/ninetypercent/</link> <comments>http://toxicsoftware.com/ninetypercent/#comments</comments> <pubDate>Sat, 04 Jun 2011 05:30:24 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category> <category><![CDATA[Development]]></category> <category><![CDATA[rant]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=511</guid> <description><![CDATA[Time to bring this blog back from the dead with a little pre-WWDC controversy! Apparently there&#8217;s a disturbing trend going on in the Cocoa development community. We old timers aren&#8217;t being excellent to each other &#38; newcomers to the community. &#8230; <a href="http://toxicsoftware.com/ninetypercent/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>Time to bring this blog back from the dead with a little pre-WWDC controversy!</p><p>Apparently there&#8217;s a disturbing trend going on in the Cocoa development community. We old timers aren&#8217;t being excellent to each other &amp; newcomers to the community. Marcus Zarra in his blog, &#8220;Cocoa is My Girlfriend&#8221;, declaims against the criticism his work on The Daily iPad app received when it was released and is dismayed this criticism is coming from predominately the &#8220;grey beards&#8221;.</p><p>I think I&#8217;m firmly in the group of &#8220;grey beards&#8221; Marcus rails against, because of two facts: I am a miserable old curmudgeon and when The Daily first came out I was very critical of it (and in fact a critical tweet of mine managed to get the product I work on <a href="http://daringfireball.net/linked/2011/02/04/inkling">grubered</a>).</p><p>Marcus spends a significant portion of his blog post elaborating on this trend, explaining how the older developers are turning on one another and their creations. For the rest of the blog post Marcus explains, well defends really, his work on The Daily.</p><p>You can read it all on his blog here: <a href="http://www.cimgf.com/2011/06/03/why-so-serious/">http://www.cimgf.com/2011/06/03/why-so-serious/</a></p><p>I think Marcus is wrong. I&#8217;m not going to accept his portrayal of this portion of the Mac OS X/iOS development community. I think the veterans in the community are no more or less critical today than they have ever been. As a general rule I think developers are highly critical by nature and by training, we have to be. And as a flip side to that, developers have to learn not to take all criticism personally.</p><p>We spend all day being told (by a program no less) how many errors we&#8217;ve just made writing a certain piece of code. When we finally fix all the obvious mistakes and can run the software, we hand the fruits of our labours off to folks whose very job is to be painstakingly critical of our work. When they find problems with our work (and they do, guaranteed) we track these mistakes in databases that grow to be huge mountains of preserved failures.</p><p>This is how good software is made. We become very critical of our work and of the software itself. We have to be critical so we know what we can fix and improve. If we took all this criticism personally, software developers would all be nervous wrecks. We learn to treat criticism not as accusation of failure, but as part of the process of making something good. But sometimes it is hard to do this and you get personally attached. That&#8217;s when the criticism feels like an attack on you.</p><p>Despite the dangers of taking it personally, I actually like this process. I think strong criticism is a good thing. You can&#8217;t improve something if you think it is perfect and often the creator is too involved with their creation to be able to recognize the flaws. I want to know when something I have worked on is broken, or just isn&#8217;t that great or could be done better. This is how I improve and learn. And I actually think society could benefit from becoming more critical, it seems to have become impolite to be critical. I hate to break it to you but your child is not gifted and talented.</p><p>I think Marcus is taking these criticisms personally, it probably is hard not to. He has poured a lot of time and energy into this product and it was put into the spotlight and promptly demolished by the community. The best thing he, or anyone else this position could do at this point is to prove the critics wrong. Fix the bugs or the performance problems, fix those cosmetic issues, make the software really fucking excellent. Blaming portions of the community for being overly critical is divisive and doesn&#8217;t make you or your software look any better.</p><p>I don&#8217;t envy Marcus the job though, I&#8217;ve worked as a contractor for large, megalomaniacal corporations and you can&#8217;t always control the outcome. Sometimes you have to shrug your shoulders, smile, nod and just do as the client asks, even if you know it is  going to produce a substandard outcome. That&#8217;s the nature of software consultancy.</p><p>And in the spirit of accepting criticism, comments are on for this post! (Don&#8217;t forget to criticise my indent style!)</p> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/ninetypercent/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>I name that UIColor in three!</title><link>http://toxicsoftware.com/uicolor-instrument/</link> <comments>http://toxicsoftware.com/uicolor-instrument/#comments</comments> <pubDate>Sat, 31 Jul 2010 20:41:32 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category> <category><![CDATA[Development]]></category> <category><![CDATA[Instruments]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[iphone development]]></category> <category><![CDATA[iPhoneOS]]></category> <category><![CDATA[UIColor]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=483</guid> <description><![CDATA[You&#8217;re working on a custom iPhoneOS view and you want it to use colours from the standard iPhone OS colour palette. Your first impulse is to check the defined colours in UIInterface.h &#8211; but there are only a grand total &#8230; <a href="http://toxicsoftware.com/uicolor-instrument/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>You&#8217;re working on a custom iPhoneOS view and you want it to use colours from the standard iPhone OS colour palette. Your first impulse is to check the defined colours in UIInterface.h &#8211; but there are only a grand total of five colours defined in that header. Your next and probably last impulse is to break out the colour picker and use the eye-dropper tool to sample the exact RGB value from the screen itself.</p><p>There are two problems with using an eye-dropper tool. The first problem is that by sampling the on screen pixel value you can only get the composited red, green, blue values; you cannot get the alpha value at all. If the original colour had an alpha value then the final colour you might get will not much the original colour at all. The second problem is that you can&#8217;t easily be sure that a colour you sample directly off the screen uses the same colour profile as the original.</p><p>I decided instead to use Intruments to probe the application and find out exactly what RGBA colour was being used by UIKit. I modified my project to display the element I wanted to find out the colour of (in my case it was the colour of a UITableView&#8217;s section footer label) and then ran the application through Intruments.</p><p>After a little trial and error (and some help from <a href="http://twitter.com/eridius">Kevin Ballard</a> to work out exactly how to output the RGBA values) I had an Instrument that would display all parameters passed to [UIColor initWithRed:green:blue:alpha] (<a href="/uploads/Screen-shot-2010-07-28-at-16.29.21.png">Screenshot</a>)</p><p>As you can see from the screenshot, this works almost too well, with Intruments displaying almost too much information. But it is actually quite easy to narrow down the data to exactly what you&#8217;re looking for (<a href="/uploads/Screen-shot-2010-07-28-at-16.29.01.png">screenshot</a>).</p><p>Note that you wont get all colours. Just those created via [UIColor initWithRed:green:blue:alpha:] but the same technique can easily be used to probe for colours created via other methods or even via CG functions. It&#8217;s also pretty easy to use gdb to break on the relevant symbol and print out the parameters &#8211; however once you have this instrument in place it&#8217;s really quick and easy to run through an application and capture all colours. You can even export the colours into CSV file for easy manipulation.</p><p>You can download the Instrument <a href="/uploads/3433F2D0_2397_4AAD_AAE8_9362671FD43A.instrument">here</a>, copy it to<pre>~/Library/Application Support/Instruments/PlugIns/Instruments</pre>and then drag the instrument from Instruments Library into your workflow.</p> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/uicolor-instrument/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>I wouldn&#8217;t hire an iPhone developer who charges less than $999.95/hour</title><link>http://toxicsoftware.com/i-wouldnt-hire-an-iphone-developer-who-charges-less-than-999-95hour/</link> <comments>http://toxicsoftware.com/i-wouldnt-hire-an-iphone-developer-who-charges-less-than-999-95hour/#comments</comments> <pubDate>Fri, 25 Jun 2010 03:50:53 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=464</guid> <description><![CDATA[If you followed the link from Mike Lee&#8217;s &#8220;motherfucker&#8221; blog to here, welcome! You&#8217;re probably looking for the iPhoneSWPro link. There you&#8217;ll be able to find out how to hire competent, professional, ego-free (for certain values of free) iPhone (and &#8230; <a href="http://toxicsoftware.com/i-wouldnt-hire-an-iphone-developer-who-charges-less-than-999-95hour/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>If you followed the link from Mike Lee&#8217;s &#8220;<a href="http://www.atomicwang.org/motherfucker/Index/Entries/2010/6/24_What_money_can_buy.html">motherfucker</a>&#8221; blog to here, welcome! You&#8217;re probably looking for the <a href="/iPhoneSWPro">iPhoneSWPro link</a>. There you&#8217;ll be able to find out how to hire competent, professional, ego-free (for certain values of free) iPhone (and iPad) developers (for somewhat south of $1000/hour).</p><p>Of course, if you want the best iOS developer money can buy, then please, hire Mike. Rest assured, you will get the best of the best. Don&#8217;t believe me? Just ask Mike.</p> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/i-wouldnt-hire-an-iphone-developer-who-charges-less-than-999-95hour/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Add to Pinboard</title><link>http://toxicsoftware.com/add-to-pinboard/</link> <comments>http://toxicsoftware.com/add-to-pinboard/#comments</comments> <pubDate>Thu, 17 Dec 2009 15:12:37 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category> <category><![CDATA[pinboard]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=450</guid> <description><![CDATA[In my previous post I suggested adapting my Python script for use in a Snow Leopard service. I decided to quickly whip this up myself. So here is a (Snow Leopard only!) service that can add URLs to pinboard.in. Unzip &#8230; <a href="http://toxicsoftware.com/add-to-pinboard/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>In my <a href="http://toxicsoftware.com/wordpress/uploads/Add%20to%20pinboard.zip">previous post</a> I suggested adapting my Python script for use in a Snow Leopard service. I decided to quickly whip this up myself. So <a href="http://toxicsoftware.com/wordpress/uploads/Add%20to%20pinboard.zip">here is</a> a (Snow Leopard only!) service that can add URLs to <a href="http://pinboard.in">pinboard.in</a>. Unzip the file and copy it to ~/Library/Services then run this little shell script to set up a keychain item for your pinboard account:</p><pre><code>#!/bin/sh

HOST=api.pinboard.in
read -p "Username: " USERNAME
read -p "Password: " -s PASSWORD
security add-internet-password -U -r http -s "$HOST" -a "$USERNAME" -w "$PASSWORD"
</code></pre><p>And the script also uses the <a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup 3rd party</a> python module to extract the title of the webpage you&#8217;re linking to. You&#8217;ll need to install beautiful soup:</p><pre><code>sudo easy_install beautifulsoup
</code></pre><p>If you&#8217;ve correctly installed the service you can enable/disable it and assign it a keyboard shortcut from the Keyboard preference pane:</p><div style="text-align:center;"><a href="http://www.flickr.com/photos/61285556@N00/4192220957" title="View 'Screen shot 2009-12-17 at 10.09.36' on Flickr.com"><img border="0" width="100" alt="Screen shot 2009-12-17 at 10.09.36" src="http://farm5.static.flickr.com/4044/4192220957_32687ff498_t.jpg" height="91"/></a></div><p>When enabled you should be able to see an entry in the application&#8217;s service menu:</p><div style="text-align:center;"><a href="http://www.flickr.com/photos/61285556@N00/4192209095" title="View 'Screen shot 2009-12-17 at 10.03.06' on Flickr.com"><img border="0" width="100" alt="Screen shot 2009-12-17 at 10.03.06" src="http://farm3.static.flickr.com/2783/4192209095_7bf4b12223_t.jpg" height="51"/></a></div> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/add-to-pinboard/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Webloc to Pinboard</title><link>http://toxicsoftware.com/webloc-to-pinboard/</link> <comments>http://toxicsoftware.com/webloc-to-pinboard/#comments</comments> <pubDate>Thu, 17 Dec 2009 14:34:40 +0000</pubDate> <dc:creator>schwa</dc:creator> <category><![CDATA[Default]]></category> <category><![CDATA[hazel]]></category> <category><![CDATA[pinboard]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[url]]></category> <category><![CDATA[webloc]]></category><guid isPermaLink="false">http://toxicsoftware.com/?p=445</guid> <description><![CDATA[If I want to keep a URL around for later I generally drag the URL from Safari&#8217;s URL bar onto the desktop. This creates an &#8220;internet clipping file&#8221; (with a .webloc file extension). These files are like little self contained &#8230; <a href="http://toxicsoftware.com/webloc-to-pinboard/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description> <content:encoded><![CDATA[<p>If I want to keep a URL around for later I generally drag the URL from Safari&#8217;s URL bar onto the desktop. This creates an &#8220;internet clipping file&#8221; (with a .webloc file extension). These files are like little self contained bookmarks that, when double clicked open the linked webpage in Safari. Because they&#8217;re just ordinary files, you can manage them like any other file, store them in folders, copy them around, delete them, etc.</p><p>Eventually these clippings will get deleted or filed in a folder and forgotten. In the past I&#8217;ve written Spotlight importers to try and gather all these clippings and then export them in a format I could use in a bookmark manager application, such as WebNoteHappy. But most bookmark manager apps tend to be quite limited and I&#8217;ve found online services such as <a href="http://delicious.com">delicious</a>, <a href="http://instapaper.com">instapaper</a> and now <a href="http://pinboard.in">pinboard.in</a> to be far superior to any desktop application.</p><p>But getting from an internet clipping on my desktop to an entry in an online bookmark manager usually involves a lot of manual labour.</p><p>I&#8217;ve found a great solution using <a href="http://www.noodlesoft.com/hazel.php">Hazel</a> and a custom Python script. I have a Hazel rule that finds files with a &#8220;.webloc&#8221; file extension on my desktop. The rule then runs a single python script to add the URL to my pinboard.in account and then moves the file into the trash. Usually Hazel notices the clipping, adds it to pinboard.in and trashes the file within a couple of seconds.</p><div style="text-align:center;"><a href="http://www.flickr.com/photos/61285556@N00/4192151805" title="View 'Screen shot 2009-12-17 at 09.12.35' on Flickr.com"><img border="0" width="100" alt="Screen shot 2009-12-17 at 09.12.35" src="http://farm3.static.flickr.com/2495/4192151805_d5b0ce0737_t.jpg" height="77"/></a></div><p>The python script is where all the magic happens:</p><pre><code>#!/usr/bin/python

import sys
import urllib
import urllib2
import re
import subprocess
import Foundation
from Carbon import File, Files, Res

def infoForWebloc(inPath):
    theDisplayName = Foundation.NSFileManager.defaultManager().displayNameAtPath_(inPath)
    resNum = Res.FSOpenResourceFile(inPath, File.FSGetResourceForkName(), Files.fsRdPerm)
    Res.UseResFile(resNum)
    theResource = Res.Get1Resource('url ', 256)
    theURLFromResource = theResource.data
    Res.CloseResFile(resNum)
    theData = Foundation.NSData.dataWithContentsOfFile_(inPath)
    thePropertyList = Foundation.NSPropertyListSerialization.propertyListWithData_options_format_error_(theData, 0, None, None)
    theURLFromData = thePropertyList['URL'] 
    return theDisplayName, theURLFromResource

def getAccount(inServer):
    theArguments = ['security', 'find-internet-password', '-s', inServer, '-g']
    thePipe = subprocess.Popen(theArguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    theOutput = thePipe.stdout.read()
    theMatch = re.search(r'"acct"&lt;blob&gt;="(.+)"', theOutput)
    theUsername = theMatch.groups()[0]
    theOutput = thePipe.stderr.read()
    theMatch = re.match(r'^password: "(.+)"$', theOutput)
    thePassword = theMatch.groups()[0]
    return theUsername, thePassword

def upload(inURL, inDescription):
    password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
    top_level_url = "https://api.pinboard.in/v1"
    theUsername, thePassword = getAccount('api.pinboard.in')
    password_mgr.add_password(None, top_level_url, theUsername, thePassword)
    handler = urllib2.HTTPBasicAuthHandler(password_mgr)
    opener = urllib2.build_opener(handler)
    inURL = urllib.quote(inURL)
    inDescription = urllib.quote(inDescription)
    theURL = 'https://api.pinboard.in/v1/posts/add?url=%s&amp;shared=no&amp;replace=yes&amp;description=%s' % (inURL, inDescription)
    theResult = opener.open(theURL)

def main(args):
    for thePath in args:
        theDescription, theURL = infoForWebloc(thePath)
        upload(theURL, theDescription)

if __name__ == '__main__':
    main(sys.argv[1:])
</code></pre><p>This script reads the .webloc file to extract the URL (.webloc files store the URL in both the Carbon resource fork and in the data fork in a property list format, this script extracts the URL from both locations but only uses the URL from the resource fork.</p><p>Then script uploads the URL to pinboard.in via pinboard.in&#8217;s delicious style API. The script gets your pinboard.in username and password from your keychain. To add the username and password to your keychain you&#8217;ll want to run this little shell script.</p><pre><code>#!/bin/sh

HOST=api.pinboard.in
read -p "Username: " USERNAME
read -p "Password: " -s PASSWORD
security add-internet-password -U -r http -s "$HOST" -a "$USERNAME" -w "$PASSWORD"
</code></pre><p>You can download the Hazel rule <a href="http://toxicsoftware.com/wordpress/uploads/Desktop.hazelrules.zip">here</a>, but do remember to set up your pinboard.in keychain item before installing it.</p><p>Instead of using the entire desktop as a sort of a dropbox for URLs you could easily adapt the script and put it into a automator action or perhaps a system service.</p> ]]></content:encoded> <wfw:commentRss>http://toxicsoftware.com/webloc-to-pinboard/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: basic
Database Caching using disk: basic
Object Caching 576/653 objects using disk: basic

Served from: toxicsoftware.com @ 2012-02-03 22:07:58 -->
