<?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>The Omni Mouth &#187; Tim</title>
	<atom:link href="http://blog.omnigroup.com/author/tim/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.omnigroup.com</link>
	<description>The Omni Mouth: standing outside your bedroom window playing \&#34;In Your Eyes\&#34; since 2006.</description>
	<lastBuildDate>Thu, 25 Feb 2010 22:34:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Intern at Omni!</title>
		<link>http://blog.omnigroup.com/2009/02/06/intern-at-omni/</link>
		<comments>http://blog.omnigroup.com/2009/02/06/intern-at-omni/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 20:34:21 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Job Filled]]></category>
		<category><![CDATA[Mac OS X Development]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/?p=488</guid>
		<description><![CDATA[We&#8217;re looking for one or two software development interns for this summer!  Check out our open positions for more info on internships or full-time employment.
]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re looking for one or two software development interns for this summer!  Check out our <a href="http://www.omnigroup.com/company/jobs/">open positions</a> for more info on internships or full-time employment.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2009/02/06/intern-at-omni/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Animating CALayer content</title>
		<link>http://blog.omnigroup.com/2008/11/14/animating-calayer-content/</link>
		<comments>http://blog.omnigroup.com/2008/11/14/animating-calayer-content/#comments</comments>
		<pubDate>Fri, 14 Nov 2008 18:47:41 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Mac OS X Development]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/?p=430</guid>
		<description><![CDATA[Out of the box, CALayer supports many animatable properties where a change will automatically create a CAAnimation for that property. But, if you look at the list of properties, it is clear that they are all of the form “stuff that OpenGL does while compositing” and have nothing to do with the inner texture representing [...]]]></description>
			<content:encoded><![CDATA[<p>Out of the box, <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span> supports many animatable properties where a change will automatically create a <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CAAnimation</span> for that property. But, if you look at the list of properties, it is clear that they are all of the form “stuff that OpenGL does while compositing” and have nothing to do with the inner texture representing your content. You are entirely responsible for telling CoreAnimation when your content has changed.</p>
<p>Recently I wanted to write a layer that had its content animate, but as far as I could determine <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span> doesn&#8217;t support this out of the box, though it is really pretty close. If you add an <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">@dynamic</span> property to a <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span> subclass and set it, your layer will be sent <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">-actionForKey:</span> and the returned animation will be passed to your <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">-addAnimation:forKey:</span>.</p>
<p>The problem is that <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span> doesn&#8217;t know that this change means it needs to update your <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">contents</span> property too, so the animation will happen but no display change will happen.</p>
<p>The API on <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span> really isn&#8217;t sufficient for this task, so it isn&#8217;t too surprising it isn&#8217;t supported. Since <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span> is a generic KVC container you can squirrel away random keys/value pairs in it and use them for whatever purposes you want.  But it has no way of knowing that a particular property change should provoke an update to the content, and updating the content unnecessarily would seriously hurt performance.</p>
<p>I&#8217;ve whipped up <a title="LayerContentAnimation-20081114.zip" href="http://blog.omnigroup.com/wp-content/uploads/2008/11/layercontentanimation-20081114.zip">some sample code</a> with a superclass that shows one approach to handling this.</p>
<p>The sample subclass looks like:</p>
<pre style="font-family:Courier;font-size:9pt;color:#444;font-weight:bold;margin-left:8px;padding-left:8px;border-left-style:solid;border-color:#edc;background-color:#fefefe">@interface WaveLayer : ContentAnimatingLayer
@property CGFloat phase, frequency, amplitude;
@end

@implementation WaveLayer
@dynamic phase, frequency, amplitude;

+ (NSSet *)keyPathsForValuesAffectingContent;
{
    static NSSet *keys = nil;
    if (!keys)
        keys = [[NSSet alloc] initWithObjects:@"phase",
                   @"frequency", @"amplitude", nil];
    return keys;
}

- (void)drawInContext:(CGContextRef)ctx;
{
    … draw a sine wave …
}
@end</pre>
<p> </p>
<p>The <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">ContentAnimatingLayer</span> superclass provides some bookkeeping and basic support for updating the content when the content-affecting properties are changed. First, it adds support for <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">-actionFor&lt;Key&gt;</span>; like many other key-based Cocoa protocols (Radar #6372335). On top of this, it adds support for determining which properties are content-affecting with <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">+keyPathsForValuesAffectingContent</span> and <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">-isContentAnimation:</span>. Active content-affecting animations are then tracked and an update timer is fired when there is at least one such animation.</p>
<p>This makes it as easy as I&#8217;d hoped it would be to write content animating layers; hopefully you&#8217;ll find this useful too!  I&#8217;ve asked Apple to add this to <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span> in the future.  If you&#8217;d like it too, you can reference my Radar #6372372.</p>
<p>The sample code is just that, my first cut at a sample. Some possible issues/improvements:</p>
<ul>
<li>The <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">-actionFor&lt;Key&gt;</span> support may or may not be fast enough (or really not even necessary).</li>
<li>Instead of following the class-based KVO customization pattern, <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">CALayer</span>s are often customized by the delegate.  So, the <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">NSSet</span>-returning method should maybe be an instance method or maybe the<span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap"> -isContentAnimation:</span> should be split up and call a new <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">-layer:isContentAnimatingKey:</span> delegate method.</li>
<li>It would be nicer to tie into the normal CoreAnimation timing mechanism instead of creating a per-instance <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">NSTimer</span>. Even without that, it might be a bit more efficient to have a single animation timer for all instances of <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">ContentAnimatingLayer</span>. Also, right now the timer doesn&#8217;t get registered for the event tracking runloop mode, though it maybe should.</li>
<li>This approach assumes that a change to a content-affecting key requires the entire content be redrawn.  This may or may not be the case for any particular layer.  A change to a content-animating property might want to specify an <span class="code" style="font-family:Courier;color:#444;font-weight:bold;white-space:nowrap">NSRect</span>-based animation that describes the dirty area.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2008/11/14/animating-calayer-content/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Using frameworks in iPhone applications</title>
		<link>http://blog.omnigroup.com/2008/10/01/using-frameworks-in-iphone-applications/</link>
		<comments>http://blog.omnigroup.com/2008/10/01/using-frameworks-in-iphone-applications/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 17:59:21 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Mac OS X Development]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2008/10/01/using-frameworks-in-iphone-applications/</guid>
		<description><![CDATA[Now that the iPhone NDA is being lifted, we can share a few of the lessons we&#8217;ve learned while working with the SDK.
Since OmniFocus makes extensive use of the Omni Frameworks, one of the very first challenges we hit when starting with the SDK was how to structure our source and Xcode projects so that [...]]]></description>
			<content:encoded><![CDATA[<p>Now that the <a href="http://developer.apple.com/iphone/program/">iPhone NDA is being lifted</a>, we can share a few of the lessons we&#8217;ve learned while working with the SDK.</p>
<p>Since OmniFocus makes extensive use of the <a href="http://www.omnigroup.com/developer/">Omni Frameworks</a>, one of the very first challenges we hit when starting with the SDK was how to structure our source and Xcode projects so that we could re-use some of our battle-tested common code between OmniFocus on the Mac and on the iPhone. Some people like splitting up their source into frameworks and some don&#8217;t. That&#8217;s all good, but on the iPhone 3rd party developers have no supported way to build their own frameworks.</p>
<p>Many limitations also come with a benefit, and in this case it is smaller application packages.  A framework may include classes or categories that are used in several clients, but not all of them.  On the iPhone, we want fast downloads from the App Store (possibly over the cell network) and we want fast startup times.  Both of these require us to not bloat our executable with code not specifically used by our app.</p>
<p>Given that we can&#8217;t use real frameworks bundles, we need to directly include our framework source in our iPhone project.  I&#8217;ll describe an approach that&#8217;s worked well for us and might suit you too.</p>
<p>First, we want to be sure that we don&#8217;t pick up any extra headers that we didn&#8217;t intend to use.  For example, if our OmniFoundation NSSet category imports another extension header, we want to be sure that we consider that change rather than just letting the dependency creep in (if nothing else, we need to build the corresponding .m file).  One approach that helps with this is to use &lt;&#8230;&gt; instead of &#8220;&#8230;&#8221; imports, so we have:</p>
<pre>
#import &lt;OmniFoundation/NSSet-OFExtensions.h&gt;
</pre>
<p>This ensures that Xcode finds our header from a “public” location rather than finding it relative to the file being compiled.  Now, if we do have an internal header that shouldn&#8217;t be published, we can leave it in an &#8220;&#8230;&#8221; import, but we have to take care to add those .m files to the target.</p>
<p>Second, we want to “publish” the headers for the public headers necessary to build the subset of the framework we&#8217;ll be using.  We accomplish this with a sequence of Build Phases in our OmniFocus target in Xcode:</p>
<p><img src="http://blog.omnigroup.com/wp-content/uploads/2008/10/omnifocus-for-iphone-target-list.png" alt="OmniFocus for iPhone Target List.png" border="0" width="278" height="291" /></p>
<p>
The first interesting phase, Create Header Directories, gives us a place in our build area for the headers:</p>
<pre>
FRAMEWORK_HEADER_BASE="$DERIVED_SOURCES_DIR/FrameworkHeaders"
mkdir -p "$FRAMEWORK_HEADER_BASE"
mkdir -p "$FRAMEWORK_HEADER_BASE"/OmniBase
mkdir -p "$FRAMEWORK_HEADER_BASE"/OmniFoundation
mkdir -p "$FRAMEWORK_HEADER_BASE"/XMLData
mkdir -p "$FRAMEWORK_HEADER_BASE"/OmniFocusModel
mkdir -p "$FRAMEWORK_HEADER_BASE"/OODataTypes
mkdir -p "$FRAMEWORK_HEADER_BASE"/OmniDataObjects
</pre>
<p>
Then, for each “framework” we have a Copy Files build phase that is set to copy to the header directory in question.  For example, Copy OmniBase Headers looks like:</p>
<p><img src="http://blog.omnigroup.com/wp-content/uploads/2008/10/copy-omnibase-headers.png" alt="Copy OmniBase Headers.png" border="0" width="429" height="60" /></p>
<p>
Finally, we need to let Xcode find the headers when it builds our target.  Opening the Target Info editor for our iPhone app, we can double-click the Header Search Path entry and add the top level FrameworkHeaders directory:</p>
<p><img src="http://blog.omnigroup.com/wp-content/uploads/2008/10/header-search-path.png" alt="Header Search Path.png" border="0" width="396" height="221" /></p>
<p>
Now we can add just the framework headers and source files we need to our iPhone project.  Each “public” header can then be dragged into the appropriate Copy Files build phase for installation during builds.</p>
<p>This isn&#8217;t the end of the road, but it is a good start.  Other issues involve making sure that your NSError domain strings aren&#8217;t dependent on your bundle identifier (since on the Mac they&#8217;ll be in different bundles and on the iPhone not), resource location (again, due to the one bundle vs. many difference on the platforms), and generating strings files when your sources are spread around (there are a couple scripts floating around for doing this; once we clean ours up we&#8217;ll hopefully publish it).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2008/10/01/using-frameworks-in-iphone-applications/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>KVO issue with subclassing</title>
		<link>http://blog.omnigroup.com/2008/09/24/kvo-issue-with-subclassing/</link>
		<comments>http://blog.omnigroup.com/2008/09/24/kvo-issue-with-subclassing/#comments</comments>
		<pubDate>Wed, 24 Sep 2008 22:30:53 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Mac OS X Development]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2008/09/24/kvo-issue-with-subclassing/</guid>
		<description><![CDATA[Dave Dribin posted a nice article on  Proper Key-Value Observer Usage that you should definitely check out. Something he mentioned in passing has been bugging me for a while:

You could check the object that&#8217;s passed in as well. Unfortunately, this doesn&#8217;t help the case where a subclass or superclass has registered a notification on [...]]]></description>
			<content:encoded><![CDATA[<p>Dave Dribin posted a nice article on <a href="http://www.dribin.org/dave/blog/archives/2008/09/24/proper_kvo_usage/"> Proper Key-Value Observer Usage</a> that you should definitely check out. Something he mentioned in passing has been bugging me for a while:</p>
<blockquote><p>
You could check the object that&rsquo;s passed in as well. Unfortunately, this doesn&rsquo;t help the case where a subclass or superclass has registered a notification on the same key path of the same object.</p>
<p>If, however, you specify something unique for the context, you can use that to correctly identify your notifications.
</p></blockquote>
<p>Proper use of the KVO context will allow a single object to subscribe to a key across a parent and child class in some common cases, but there is a hidden danger.  If your two classes both follow the basic pattern of adding an observation when your object is created and removing it when your object is dying, all will be well.  But if you have a class that may toggle its observation on and off based on some varying criteria, you can get in trouble.</p>
<p>The core of the problem is an API flaw in KVO; -removeObserver:forKeyPath: doesn&#8217;t include a context argument.  So, if you have an object that is subscribed to a key twice, with two different context pointers, there is no way to specify which one is to be removed.  If your object is dying and cleaning up all observations, this isn&#8217;t a big deal.  But if your subclass logic wants to temporarily turn off its observation, it has no way to make sure that&#8217;s what happens &mdash; it might instead end up removing the superclass observation.</p>
<p>Now, granted this is a relatively rare case that can be accounted for in your design.  But, this takes an otherwise general and extremely useful API and adds a bit of worry to it every time you use it.  You can&#8217;t use it locally in a class without worrying about what your super- and subclasses are doing.</p>
<p>I&#8217;ve written up Radar 6244260 on this, including a <a href="http://blog.omnigroup.com/wp-content/uploads/2008/09/multikvowithdifferentcontexts.zip" title="MultiKVOWithDifferentContexts.zip">test case</a>.  Hopefully they&#8217;ll add a proper -removeObserver:forKeyPath:context: and deprecate the current method for some future release.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2008/09/24/kvo-issue-with-subclassing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>More objc method tracing</title>
		<link>http://blog.omnigroup.com/2008/01/27/more-objc-method-tracing/</link>
		<comments>http://blog.omnigroup.com/2008/01/27/more-objc-method-tracing/#comments</comments>
		<pubDate>Sun, 27 Jan 2008 23:44:32 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Mac OS X Development]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2008/01/27/more-objc-method-tracing/</guid>
		<description><![CDATA[Bill Bumgarner has posted a few great articles on Objective-C method tracing using dtrace:

Objective-C: Printing Class Name from Dtrace
Objective-C: Using Instruments to trace messages-to-nil

I have a internal tool at Omni that traces message sends by creating new method IMPs to wrap the existing ones in a trampoline, but it requires some nasty assembly stubs and [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.friday.com/bbum/">Bill Bumgarner</a> has posted a few great articles on Objective-C method tracing using dtrace:</p>
<ul>
<li><a href="http://www.friday.com/bbum/2008/01/26/objective-c-printing-class-name-from-dtrace">Objective-C: Printing Class Name from Dtrace</a></li>
<li><a href="http://www.friday.com/bbum/2008/01/04/objective-c-using-instruments-to-trace-messages-to-nil/">Objective-C: Using Instruments to trace messages-to-nil</a></li>
</ul>
<p>I have a internal tool at Omni that traces message sends by creating new method IMPs to wrap the existing ones in a trampoline, but it requires some nasty assembly stubs and has only ever worked on Sparc, ppc and x86.  It is very fast, but hard to maintain and a little fragile (and doesn&#8217;t handle the nil case).  A 90% solution can be obtained by extending Bill and other&#8217;s work.</p>
<p><a href="http://people.omnigroup.com/kc/">Ken</a> sent out a partial tracing solution this morning and finally got me off my keister.  Here is a D script that catches ObjC message sends and dumps a OPML fragment (which can then be wrapped in the XML goo via an external shell script or whatever) and then viewed in <a href="http://www.omnigroup.com/omnioutliner/">OmniOutliner</a>.</p>
<p>Download: <a href="http://blog.omnigroup.com/wp-content/uploads/2008/01/objc-trace-opml.d.gz" title="objc-trace-opml.d.gz">objc-trace-opml.d.gz</a></p>
<p>This isn&#8217;t a perfect solution by any means.  Some of the issues:</p>
<ul>
<li>This has to be run in an essentially single-threaded program; any background threads must be totally quiescent or you&#8217;ll get a mixture of output from multiple threads.  It wouldn&#8217;t be too hard to modify this script to include a thread identifier or maybe just filter out anything from background threads.</li>
<li>This won&#8217;t handle exceptions correctly; they&#8217;ll break the OPML nesting.  Our internal tool handles this, but since NSError arrived on the scene, this is less of an issue.  Just avoid tracing code with exceptions.</li>
<li>dtrace is <strong>slow</strong> when matching all entries in the objc provider.  The startup time on this script is something like 40 seconds on my machine.  Annoying, but not the worst thing ever, since you are likely to trace once and then spend a fair bit of time examining the results.</li>
<li>This particular variant of the script will only work on x86 due to the hacky way I check for objc_msgSend_stret.</li>
<li>dtrace can overflow its buffer and drop events when there are massive numbers of probe hits.  Run with a big buffer and trace only the exact set of methods you need.  Ideally you&#8217;ll be running in the debugger, stop right before where you need to trace turn on tracing and then &#8216;next&#8217; over one or two lines of code.  The &#8216;-b&#8217; flag to dtrace can also be used to increase the buffer size.</li>
</ul>
<p>Some of the nice bits:</p>
<ul>
<li>No assembly-fu required.</li>
<li>Call hierarchy is preserved and can be expanded/hoisted and such in <a href="http://www.omnigroup.com/omnioutliner/">OmniOutliner</a>.</li>
<li>Both the class of the receiver and the class of the method implementation are included.  So, you can see that +[MySuperclass initialize] is getting called on MySubcass, for example.</li>
<li>All method invocations are shown, so you can see nested calls to super instead of just the initial call to objc_msgSend.  I&#8217;ve not tested whether cached method IMPs get traced too; <i>normal</i> code should get traced as expected.  Swizzling, IMP caching or dynamically registering methods will possibly not work as well.</li>
<li>The pointer value of the receiver is emitted.  By the time you examine the output, it might be dead and gone, but a surprising amount of the time it isn&#8217;t.  For example, things like static NSStrings, NSScriptClassDescriptions, interface widgets and other cache-once data may still be around for submitting to &#8216;po&#8217; in the debugger.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2008/01/27/more-objc-method-tracing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Senior Coder gig available</title>
		<link>http://blog.omnigroup.com/2008/01/24/senior-coder-gig-available/</link>
		<comments>http://blog.omnigroup.com/2008/01/24/senior-coder-gig-available/#comments</comments>
		<pubDate>Thu, 24 Jan 2008 21:18:42 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Job Filled]]></category>
		<category><![CDATA[Mac OS X Development]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2008/01/24/senior-coder-gig-available/</guid>
		<description><![CDATA[We finally have space to grow, now that we&#8217;ve moved to our new office!  There is no specific position to fill, but rather we are content to wait until we find someone who will fit well into our team.  Take a look at what working at Omni is like and the general description [...]]]></description>
			<content:encoded><![CDATA[<p>We finally have space to grow, now that we&#8217;ve moved to our new office!  There is no specific position to fill, but rather we are content to wait until we find someone who will fit well into our team.  Take a look at <a href="http://www.omnigroup.com/company/jobs/#WhatIsOmniLike">what working at Omni is like</a> and the general description of <a href="http://www.omnigroup.com/company/jobs/#SeniorCoder">who we are seeking</a> to see if this is the right place for you!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2008/01/24/senior-coder-gig-available/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Preventing Services from activating your application</title>
		<link>http://blog.omnigroup.com/2007/11/29/preventing-services-from-activating-your-application/</link>
		<comments>http://blog.omnigroup.com/2007/11/29/preventing-services-from-activating-your-application/#comments</comments>
		<pubDate>Thu, 29 Nov 2007 09:59:44 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Mac OS X Development]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2007/11/29/preventing-services-from-activating-your-application/</guid>
		<description><![CDATA[I failed to find any way to do this via the internets; but gdb, and some kindly soul inside Apple, met the challenge:

(gdb) b -[NSUserDefaults objectForKey:]
Breakpoint 17 at 0x94172fa4
(gdb) c
Continuing.
... invoke service, hit breakpoint ...
(gdb) po *(id *)($fp + 16)
NSShouldActivateForServiceRequest
(gdb)

Is there a better way to do this?  Google and mdls don&#8217;t seem to know [...]]]></description>
			<content:encoded><![CDATA[<p>I failed to find any way to do this via the internets; but gdb, and some kindly soul inside Apple, met the challenge:</p>
<pre>
(gdb) b -[NSUserDefaults objectForKey:]
Breakpoint 17 at 0x94172fa4
(gdb) c
Continuing.
... invoke service, hit breakpoint ...
(gdb) po *(id *)($fp + 16)
NSShouldActivateForServiceRequest
(gdb)
</pre>
<p>Is there a better way to do this?  Google and mdls don&#8217;t seem to know about NSShouldActivateForServiceRequest at all, so I&#8217;m guessing not.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2007/11/29/preventing-services-from-activating-your-application/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Terminal scripting in 10.5</title>
		<link>http://blog.omnigroup.com/2007/11/03/terminal-scripting-in-105/</link>
		<comments>http://blog.omnigroup.com/2007/11/03/terminal-scripting-in-105/#comments</comments>
		<pubDate>Sat, 03 Nov 2007 21:55:41 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Mac OS X Development]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2007/11/03/terminal-scripting-in-105/</guid>
		<description><![CDATA[Terminal in 10.5 has seen some great scripting improvements to match its additional functionality.  Occasionally I have several Terminal sessions with some ssh&#8216;d remote servers and then I forget which Terminals are local and which are remote.
Here is a simple little command-line AppleScript that will let you set an individual Terminal&#8217;s style from the [...]]]></description>
			<content:encoded><![CDATA[<p>Terminal in 10.5 has seen some great scripting improvements to match its additional functionality.  Occasionally I have several Terminal sessions with some <code>ssh</code>&#8216;d remote servers and then I forget which Terminals are local and which are remote.</p>
<p>Here is a simple little command-line AppleScript that will let you set an individual Terminal&#8217;s style from the command line;<br />
<i>(2009-09-01: updated for Snow Leopard)</i><a href='http://blog.omnigroup.com/wp-content/uploads/2009/09/setterminalstyle-v2.zip'>setterminalstyle-v2</a></p>
<p>Put the script in your <code>PATH</code> somewhere and then add a ssh function in your <code>.zshrc</code>, or equivalent:</p>
<pre>
# Show remote Terminal sessions with a different style.
# TERM_PROGRAM doesn't get set if we are logged in remotely,
# but then the originating Terminal could have done this (hopefully).
if [ "$TERM_PROGRAM" = "Apple_Terminal" ]; then
  function ssh {
    SetTerminalStyle ssh
    /usr/bin/ssh "$@"
    SetTerminalStyle default
  }
fi
</pre>
<p>Finally, create a <code>ssh</code> Settings entry in Terminal&#8217;s preferences:</p>
<p><img src="http://blog.omnigroup.com/wp-content/uploads/2007/11/terminal-ssh-settings-set.png" height="92" width="181" border="0" alt="Terminal-ssh-settings-set.png" /></p>
<p>Other obvious commands for this include <code>sudo</code> and <code>su</code>.Using <code>RPROMPT</code> and Terminal&#8217;s <code>processes</code> scripting property on <code>tab</code> it might be possible to get this to work without the function wrappers, but executing the AppleScript on every command was a little too slow for my taste.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2007/11/03/terminal-scripting-in-105/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>OmniFocus crash statistics</title>
		<link>http://blog.omnigroup.com/2007/07/25/omnifocus-crash-statistics/</link>
		<comments>http://blog.omnigroup.com/2007/07/25/omnifocus-crash-statistics/#comments</comments>
		<pubDate>Wed, 25 Jul 2007 17:36:11 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Mac OS X Development]]></category>
		<category><![CDATA[OmniFocus]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2007/07/25/omnifocus-crash-statistics/</guid>
		<description><![CDATA[For many years now we&#8217;ve had an integrated crash reporting system.  This has helped improve the stability of our applications immensely (often report now start out with &#8220;Wow, this is the first crash I&#8217;ve seen&#8230;&#8221;).  But, it hasn&#8217;t always been clear (especially in the alpha or beta timeframe) how well we were doing [...]]]></description>
			<content:encoded><![CDATA[<p>For many years now we&#8217;ve had an integrated crash reporting system.  This has helped improve the stability of our applications immensely (often report now start out with &#8220;Wow, this is the first crash I&#8217;ve seen&#8230;&#8221;).  But, it hasn&#8217;t always been clear (especially in the alpha or beta timeframe) how well we were doing on overall stability.  We could guess by counting the number of crash reports vs. an estimate of the number of active users, but that wasn&#8217;t very convincing.</p>
<p>Near the beginning of June, I added some support to our software update and crash logging frameworks to keep track of things like:</p>
<ul>
<li>total times the application has been launched
<li>total number of crashes
<li>total amount of time the application has been running
</ul>
<p>(As always, our software update system reports its information without including any personal details, and can be disabled entirely if so desired.)</p>
<p>Using this, we can now chart the total number of hours OmniFocus has been running vs. the total number of crashes (reported or not!).  As the pool of people testing OmniFocus goes up, or some testers go idle, or some user with large number of crashes isn&#8217;t reporting them, we don&#8217;t have to wonder as much how that affects our average crash rate.</p>
<p><a href="http://blog.omnigroup.com/wp-content/uploads/2007/07/hourspercrash-internal-absolute.png "><img src="http://blog.omnigroup.com/wp-content/uploads/2007/07/hourspercrash-internal-absolute.thumbnail.png" alt="OmniFocus Hours per Crash 20070725" /></a></p>
<p>After my latest crash fix, our rate has improved to about 8000 hours per crash.  We aren&#8217;t sure yet what constitutes a reasonable lower limit for hours/crash, but this does let us notice when a fix we&#8217;ve made actually is addressing the issue.  We aren&#8217;t yet tracking the number of hours that the application is <strong>active</strong> (an hour spent hidden counts the same as an hour spent in full use).  Whether this matters, when averaged across a large number of users, is open to question.</p>
<p>Still, there are only 8760 hours in a year, so if we can get above that, we&#8217;ll be feeling pretty good.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2007/07/25/omnifocus-crash-statistics/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Writing bug reports</title>
		<link>http://blog.omnigroup.com/2007/05/15/writing-bug-reports/</link>
		<comments>http://blog.omnigroup.com/2007/05/15/writing-bug-reports/#comments</comments>
		<pubDate>Tue, 15 May 2007 19:23:54 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[OmniFocus]]></category>

		<guid isPermaLink="false">http://blog.omnigroup.com/2007/05/15/writing-bug-reports/</guid>
		<description><![CDATA[Now that OmniFocus is sticking its toes out the door, this seems like a good time to remind everyone about best practices on reporting problems.  Crash reports are especially important and should receive extra care.

Please report every single crash you hit, even if you don&#8217;t know how to reproduce it yet.  Include any [...]]]></description>
			<content:encoded><![CDATA[<p>Now that OmniFocus is sticking its toes out the door, this seems like a good time to remind everyone about best practices on reporting problems.  Crash reports are especially important and should receive extra care.</p>
<ul>
<li>Please report every single crash you hit, even if you don&#8217;t know how to reproduce it yet.  Include any details of what you were doing leading up to the crash.  We can then correlate reports from different users to narrow down the cause, even if no one person can reliably reproduce the problem.
<li>If you are comfortable doing so, include your document as a starting point (for OmniFocus, this is in ~/Library/Application Support/OmniFocus).  If you have qualms about sending your data, skipping this is OK.  Another option is to export your file to a backup and then trim down that copy to include only the portions necessary to reproduce the problem.
<li>List the exact steps to reproduce the problem, starting from the file you included or from an empty document.  It is hard to be too specific: for example, you might be tempted to say &#8220;I deleted the second task of the project &#8216;Foo&#8217;&#8221;, but this doesn&#8217;t make it clear whether you used the delete key, a main menu item, a context menu, invoked an AppleScript, or picked up the task and dragged it to the trash.  In some cases, the distinction matters.  When in doubt, describe the physical actions you used (&#8221;press key X&#8221;, &#8220;clicked button Y&#8221;).
<li>If the proper behavior isn&#8217;t obvious (&#8221;don&#8217;t crash&#8221;), tell us what you expected to happen.  Maybe you have a perspective on a design question we haven&#8217;t considered or that we should reconsider.
</ul>
<p>With crash reports in particular, it is important to include reproducible steps.  Sometimes this isn&#8217;t possible, and that&#8217;s fine &#8212; please report the crash anyway with whatever details you have.  With a large enough pool of people, someone will be able to figure out how to reproduce it.</p>
<p>Crash reports are CC&#8217;d directly to the entire OmniFocus engineering team.  If you include reproducible steps, we&#8217;ll typically stop whatever else we&#8217;re working to fix it immediately.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.omnigroup.com/2007/05/15/writing-bug-reports/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>

