<?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>Cocoa Is My Girlfriend &#187; NSOperation</title>
	<atom:link href="http://www.cimgf.com/category/threading/nsoperation/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.cimgf.com</link>
	<description>Taglines are for Windows programmers</description>
	<lastBuildDate>Thu, 15 Jul 2010 21:20:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Core Animation Tutorial: QTMovieLayer and Image Animation</title>
		<link>http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/</link>
		<comments>http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 19:33:26 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Core Animation]]></category>
		<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[NSOperation]]></category>
		<category><![CDATA[QTKit]]></category>
		<category><![CDATA[calayer]]></category>
		<category><![CDATA[convert nsimage to cgimageref]]></category>
		<category><![CDATA[example]]></category>
		<category><![CDATA[qtmovielayer]]></category>
		<category><![CDATA[sample code]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/</guid>
		<description><![CDATA[In my first post I wrote about using NSOperation to grab an image of the current frame of a QuickTime movie while it was playing and save it out to the filesystem. Considering the excitement that is surrounding Core Animation these days, I thought it might be interesting to take that project and change it [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.cimgf.com/wp-content/uploads/2008/03/qtmovielayer_desktop.jpg' title='QTMovieLayer App Desktop'  rel='lightbox'><img src='http://www.cimgf.com/wp-content/uploads/2008/03/qtmovielayer_desktop.thumbnail.jpg' alt='QTMovieLayer App Desktop' align="left" style="margin:5px;" /></a>In my <a href="http://www.cimgf.com/2008/02/23/nsoperation-example/">first post</a> I wrote about using NSOperation to grab an image of the current frame of a QuickTime movie while it was playing and save it out to the filesystem. Considering the excitement that is surrounding Core Animation these days, I thought it might be interesting to take that project and change it to instead grab the current frame and animate it across the screen using a Core Animation layer (CALayer). I had to employ a few tricks to get it to work, but the end result, while completely useless, is quite excellent.
<br /><br /><br /><br />
&nbsp;
<br /><br /><br /><br />
<span id="more-38"></span></p>

<h2>Getting Ready For The Image</h2>

<p>The focus of this tutorial is Core Animation and specifically how to use a QTMovieLayer as well as animating an image across the screen using a CALayer. I, therefore, will not spend any time addressing NSOperation and I think we&#8217;ve covered this adequately on this site. I would suggest, however, that you familiarize yourself with <a href="http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/">Marcus&#8217; post on NSOperation</a> as he discusses calling back into the main thread once the NSOperation has completed. I employ Marcus&#8217; technique in this project so that I can be notified when the image I&#8217;m wanting to animate is ready.</p>

<blockquote>
You can download the demo project for this post from here: <a href='http://www.cimgf.com/wp-content/uploads/2008/03/movieimageflick.zip' title='Movie Image Flick Demo Project'>Movie Image Flick Demo Project</a>
</blockquote>

<p>Download the project and run it. It will prompt you to select a QuickTime movie to play. Once the movie starts playing, tap your spacebar and watch the images pop off of the movie and animate to random places on the screen. Tap the spacebar quickly to see the effect work in rapid succession.</p>

<p>As in my NSOperation post, I want the video playback to be completely flicker free. I achieve this by obtaining a reference to a copy of the QTMovie object from which I obtain the image at the given time. If you take a look at my <em>main:</em> function in my NSOperation derived class, you&#8217;ll see how I am notifying the main thread that it may now do something with the image I&#8217;ve obtained.</p>

<p><strong>ImageGrabber.m:main</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> movie <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span> image;
        image <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>movie frameImageAtTime<span style="color: #002200;">:</span><span style="color: #a61390;">time</span> 
                      withAttributes<span style="color: #002200;">:</span>imageAttrs error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>image retain<span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>AppDelegate shared<span style="color: #002200;">&#93;</span> performSelectorOnMainThread<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>imageReady<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span>
                                               withObject<span style="color: #002200;">:</span>image
                                            waitUntilDone<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>image release<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>In the second last line of the function, notice I am calling back into my main thread and letting the app delegate know that the image is ready. I am also handing the image to the <em>imageReady:</em> function. This is very convenient for what we need to do next. But first, let&#8217;s discuss drawing the layers with no backing view or window.</p>

<h2>Drawing Layers In Thin Air</h2>

<p>This project employs a trick that makes it appear as if the layers are being drawn without a backing view. This is, of course, not really possible, so instead we do a little trick. I achieved this effect by creating a borderless window with a transparent background. As usual, I want to give credit where credit is due. Lucas Newman answered a question <a href="http://theocacao.com/document.page/551">I posted on Scott Stevenson&#8217;s blog</a> to find out how Lucas did this in his demo project a the Silicon Valley CocoaHeads meeting on Core Animation. You simply create your own NSWindow derived class and override the initWithContentRect: method. Here is the resulting initialization code I came up with from his suggestion.</p>

<p><strong>BorderlessWindow.m:initWithContentRect</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span> initWithContentRect<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">NSRect</span><span style="color: #002200;">&#41;</span> contentRect
                 styleMask<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">unsigned</span> <span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span> aStyle
                   backing<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span>NSBackingStoreType<span style="color: #002200;">&#41;</span> bufferingType
                     defer<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span> flag
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>super initWithContentRect<span style="color: #002200;">:</span> contentRect 
                 styleMask<span style="color: #002200;">:</span> NSBorderlessWindowMask 
                   backing<span style="color: #002200;">:</span> bufferingType 
                   defer<span style="color: #002200;">:</span> flag<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
    <span style="color: #002200;">&#91;</span>self setBackgroundColor<span style="color: #002200;">:</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSColor</span> clearColor<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>self setOpaque<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>The only issue with using a transparent backing window/view is that you cannot click through it even though it looks like you ought to be able to. There is probably a way to pass the click on to the next front most window, but I haven&#8217;t yet researched this. I&#8217;ll let you know when I find the answer, or if you know the answer, post it in the comments.</p>

<h2>Rapid Fire Image Animation</h2>

<p>I created a method to initialize my NSOperation derived objects and hand them off to the NSOperationQueue. I hooked it up to the spacebar and can then tap the spacebar as quickly as possible and watch the images just pop off the playing movie. Here is my <em>flickIt:</em> function.</p>

<p><strong>AppDelegate.m:flickIt</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>flickIt<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    ImageGrabber <span style="color: #002200;">*</span>grabber <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>ImageGrabber alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #002200;">&#91;</span>grabber setTime<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>movie currentTime<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #11740a; font-style: italic;">// Hand off the background movie to the NSOperation derived</span>
    <span style="color: #11740a; font-style: italic;">// object</span>
    <span style="color: #002200;">&#91;</span>grabber setMovie<span style="color: #002200;">:</span>movieBak<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Add the oepration to the queue. It will be run immediately.</span>
    <span style="color: #002200;">&#91;</span>queue addOperation<span style="color: #002200;">:</span>grabber<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>This function creates the NSOpeartion derived objects and passes a reference to the current time in the playing movie as well as a reference to the background movie that I use to pull the image data from. Remember that this object is copied from the original QTMovie object and is used to keep from needing to pull the image data from the QTMovie object that is actually playing in the QTMovieLayer. Pulling the image from the QTMovie object that is being used for playback would cause the playback to stutter.</p>

<p>As stated earlier, when my image is ready, the NSOperation derived object, ImageGrabber, calls back into the main thread calling the function called <em>imageReady:</em>. Here is its implementation.</p>

<p><strong>AppDelegate.m:imageReady</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>imageReady<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #002200;">&#123;</span>    
    <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSAnimationContext</span> currentContext<span style="color: #002200;">&#93;</span> setDuration<span style="color: #002200;">:</span>1.5f<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Save off the rectangle of the ready layer before</span>
    <span style="color: #11740a; font-style: italic;">// it gets animated. We will use this to reset the</span>
    <span style="color: #11740a; font-style: italic;">// ready layer.</span>
    CGRect prevRect <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>readyLayer frame<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Convert the NSImage to a CGImageRef</span>
    CGImageRef imageRef <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self nsImageToCGImageRef<span style="color: #002200;">:</span>image<span style="color: #002200;">&#93;</span>;
    CFRetain<span style="color: #002200;">&#40;</span>imageRef<span style="color: #002200;">&#41;</span>;
    readyLayer.contents <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>imageRef;
    readyLayer.backgroundColor <span style="color: #002200;">=</span> CGColorCreateGenericRGB<span style="color: #002200;">&#40;</span>0.0f,0.0f,0.0f,1.0f<span style="color: #002200;">&#41;</span>;
    readyLayer.borderColor <span style="color: #002200;">=</span> CGColorCreateGenericRGB<span style="color: #002200;">&#40;</span>0.45f,0.45f,0.45f,1.0f<span style="color: #002200;">&#41;</span>;
    readyLayer.borderWidth <span style="color: #002200;">=</span> 4.0f;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Grab a random rectangle on the screen where our image</span>
    <span style="color: #11740a; font-style: italic;">// layer will animate to.</span>
    CGRect randRect <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self getRandomRect<span style="color: #002200;">:</span>prevRect<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>readyLayer setFrame<span style="color: #002200;">:</span>randRect<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>readyLayer setOpacity<span style="color: #002200;">:</span>1.0f<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Reset the ready layer so that it is ready for the next image</span>
    readyLayer <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>CALayer alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span> retain<span style="color: #002200;">&#93;</span>;
    readyLayer.frame <span style="color: #002200;">=</span> prevRect;
    readyLayer.opacity <span style="color: #002200;">=</span> 0.01f;
&nbsp;
    <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>window contentView<span style="color: #002200;">&#93;</span> layer<span style="color: #002200;">&#93;</span> addSublayer<span style="color: #002200;">:</span>readyLayer<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Notice that we are converting the <em>NSImage</em> that gets passed to this function into a <em>CGImageRef</em> which is what our Core Animation layer requires to set it contents. Here is the code to convert an <em>NSImage</em> to a <em>CGImageRef</em>.</p>

<p><strong>AppDelegate.m:nsImageToCGImageRef</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>CGImageRef<span style="color: #002200;">&#41;</span>nsImageToCGImageRef<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSData</span> <span style="color: #002200;">*</span> imageData <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>image TIFFRepresentation<span style="color: #002200;">&#93;</span>;
    CGImageRef imageRef;
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span>imageData<span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        CGImageSourceRef imageSource <span style="color: #002200;">=</span> 
                     CGImageSourceCreateWithData<span style="color: #002200;">&#40;</span>
                           <span style="color: #002200;">&#40;</span>CFDataRef<span style="color: #002200;">&#41;</span>imageData,  <span style="color: #a61390;">NULL</span><span style="color: #002200;">&#41;</span>;
&nbsp;
        imageRef <span style="color: #002200;">=</span> CGImageSourceCreateImageAtIndex<span style="color: #002200;">&#40;</span>
                          imageSource, <span style="color: #2400d9;">0</span>, <span style="color: #a61390;">NULL</span><span style="color: #002200;">&#41;</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">return</span> imageRef;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>Preloading A Layer to Animate</h2>

<p>Instead of creating the layer, setting its contents, and then animating it all at once, I instead set an empty layer with a near zero opacity to overlay the QTMovieLayer when the movie first loads. Then, when the user taps the spacebar, I populate that invisible layer&#8217;s contents with the image data and then animate it. This keeps me from having to create a more complicated animation to get the desired effect.</p>

<p>Once the image layer has it&#8217;s new frame set, I re-initialize the ready layer. You see the ready layer get reset with this code from the <em>imageReady:</em> function.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">// Reset the ready layer so that it is ready for the next image</span>
readyLayer <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>CALayer alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span> retain<span style="color: #002200;">&#93;</span>;
readyLayer.frame <span style="color: #002200;">=</span> prevRect;
readyLayer.opacity <span style="color: #002200;">=</span> 0.01f;
&nbsp;
<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>window contentView<span style="color: #002200;">&#93;</span> layer<span style="color: #002200;">&#93;</span> addSublayer<span style="color: #002200;">:</span>readyLayer<span style="color: #002200;">&#93;</span>;</pre></td></tr></table></div>


<blockquote>
<br />
<strong>Note:</strong> I set the opacity to near zero as when it is set to zero it won&#8217;t animate the opacity change properly. I&#8217;m looking into why this is and will update this post with what I find when I find it.
<br /><br />

&nbsp;
</blockquote>

<h2>Random Points</h2>

<p>When I animate the layers, I simply grab a random point and the screen and then scale the image down to 35% of the original. When I call <em>setFrame:</em> the magic ensues and my screen gets really cluttered with lots of images. As I said before, not very useful, but excellent. Here is the random rectangle calculation function, <em>getRandomRect:</em>.</p>

<p><strong>AppDelegate.m:getRandomRect</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>CGRect<span style="color: #002200;">&#41;</span>getRandomRect<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGRect<span style="color: #002200;">&#41;</span>startRect;
<span style="color: #002200;">&#123;</span>    
    CGPoint point <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span>random<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">%</span> 
                          <span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>NSWidth<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>window frame<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>, 
                          random<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">%</span> 
                           <span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>NSHeight<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>window frame<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> CGRectMake<span style="color: #002200;">&#40;</span>point.x, point.y, 
                 startRect.size.width <span style="color: #002200;">*</span> 0.35f, startRect.size.height <span style="color: #002200;">*</span> 0.35f<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>Conclusion</h2>

<p>The nuances of Core Animation are quite interesting and provide a fun challenge when trying to solve problems. In other words, the devil is in the details. There is probably a better way to achieve the animation code, but I felt that the solution I came up with here works pretty well. There are details about Core Animation that I am still learning, but this type of effect demonstrates exactly the kinds of interesting things that are possible.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>NSOperation Example</title>
		<link>http://www.cimgf.com/2008/02/23/nsoperation-example/</link>
		<comments>http://www.cimgf.com/2008/02/23/nsoperation-example/#comments</comments>
		<pubDate>Sat, 23 Feb 2008 06:46:05 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[NSOperation]]></category>
		<category><![CDATA[QTKit]]></category>
		<category><![CDATA[Threading]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/2008/02/23/nsoperation-example/</guid>
		<description><![CDATA[Forget Mandelbrot sets (Apple coding headstarts) and Expression Trees. NSOperation is really not that hard. In his post, Marcus introduced how to use NSOperation to greatly simplify multi-threading tasks in your application. I am now going to provide a step-by-step walk-through sample application that uses NSOperation, NSOperationQueue, and QTKit. While looking around the Internet, I [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-14.thumbnail.png' alt='QT Image Grab' border='0' style='margin:5px' align='left' /><strong>Forget Mandelbrot sets (Apple coding headstarts) and <a href="http://macresearch.org/node/4567" title="Mac Research NSOPeration Tutorial" target="_blank">Expression Trees</a>. NSOperation is really not that hard.</strong></p>

<p>In <a href="http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/">his post</a>, Marcus introduced how to use <em>NSOperation</em> to greatly simplify multi-threading tasks in your application. I am now going to provide a step-by-step walk-through sample application that uses <em>NSOperation</em>, <em>NSOperationQueue</em>, and <em>QTKit</em>.</p>

<p>While looking around the Internet, I noticed that the only examples of using <em>NSOperation</em> available were related to scientific applications. I wanted something that I could relate to a little better and since I&#8217;ve been working with <em>QTKit</em> a lot lately, I figured it would be a good framework to build from. This application simply grabs images of a movie while it is playing back and saves them out to a file. It&#8217;s pretty simple, but it shows how to do something fairly practical.
<span id="more-3"></span></p>

<h2>Grabbing Movie Image Frames</h2>

<p>The application displays a movie and provides a button for the user to click whenever the user wants to save the current frame of the movie to disk while it is playing. Here are some basic requirements I&#8217;ve given the app.</p>

<ul>
    <li>Images are only saved when the movie is playing back</li>
    <li>Clicking the button and the subsequent saving of the current image must not cause the movie to flicker</li>
    <li>Clicking in rapid succession should not cause the application to crash. For each click, a new task (operation) should be generated</li>
</ul>

<p>Here is a screenshot of the final application.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-14.png' title='QT Image Grab'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-14.thumbnail.png' alt='QT Image Grab' /></a></p>

<p>Follow along in XCode to create the application called QT Image Grab or <a href='http://www.cimgf.com/wp-content/uploads/2008/02/qtimagegrab.zip' title='Sample Project'>download the sample project here</a>.</p>

<p><strong>Note</strong> If you are already comfortable with setting up an AppDelegate class and making connections in Interface Builder, you can jump down to the section titled <a href="#derivedobject">Derive A Class From NSOperation</a></p>

<h2>Create The Application</h2>

<p>Create a Cocoa Application Using the following steps:</p>

<ol>
<li>Select <strong>File > New Projectâ€¦</strong> and choose <em>Cocoa Application</em> in the ensuing dialog. Click Next</li>
<li>Enter â€˜QTImageGrabâ€™ as the project name. Click Finish</li>
</ul>
</ol>

<p>You should see a project workspace like the following:</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/02/project.png' title='New Project Workspace'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/project.thumbnail.png' alt='New Project Workspace' /></a></p>

<h2>Create A Controller/Delegate Class</h2>

<p>The next thing you need to do is create an application controller, or delegate. To do so, use the following steps:</p>

<ol>
<li><strong>Option-Click</strong> on the <em>Classes</em> folder in your workspace and select &#8216;Add File&#8230;&#8217;

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-2.png' title='Add New Objective-C Class'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-2.thumbnail.png' alt='Add New Objective-C Class' /></a>
</li>
<li>Choose <strong>Object-C Class</strong> in the ensuing dialog and click <strong>Next</strong></li>

<li>Name the file &#8216;AppDelegate.m&#8217; and click <strong>Finish</strong></li>

<li>A new code window will display with your &#8216;AppDelegate&#8217; interface code (.h file). Edit the code so that it looks like this:


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
<span style="color: #6e371a;">#import &lt;QTKit/QTKit.h&gt;</span>
<span style="color: #6e371a;">#import &lt;QuartzCore/CoreAnimation.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> AppDelegate <span style="color: #002200;">:</span> <span style="color: #400080;">NSObject</span> <span style="color: #002200;">&#123;</span>
	IBOutlet QTMovieView <span style="color: #002200;">*</span>movieView;
	IBOutlet <span style="color: #400080;">NSTextField</span> <span style="color: #002200;">*</span>outputPath;
	IBOutlet <span style="color: #400080;">NSWindow</span> <span style="color: #002200;">*</span>window;
&nbsp;
	<span style="color: #400080;">NSOperationQueue</span> <span style="color: #002200;">*</span>operationQueue;
	QTMovie <span style="color: #002200;">*</span>imagesMovie;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>grab<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>openMovie<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>selectOutputDir<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>



</li>

<li>Now we need to add the QTKit framework to your project. Option-Click the Frameworks folder in your project and select <strong>Add > Existing Frameworks&#8230;</strong>

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-3.png' title='Add Existing Frameworks'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-3.thumbnail.png' alt='Add Existing Frameworks' /></a>

In the ensuing dialog, navigate to <strong>/System/Library/Frameworks</strong> and select <strong>QTKit.framework</strong>.

Click <strong>Add</strong>

<li>Now switch over to your implementation file for &#8216;AppDelegate&#8217; (.m file). Add the implementation code so that the file looks like this:<br />


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> AppDelegate
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>awakeFromNib;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// We're going to add some initialization code here</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>grab<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// This is where will will start the process for grabbing the current image.</span>
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>openMovie<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Here we load our movie using an open panel dialog.</span>
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>selectOutputDir<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Here we will select an output directory where the current frame</span>
    <span style="color: #11740a; font-style: italic;">// image will be saved to.</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// We're going to have some cleanup to do.</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>



<br />
We will actually add some code to do something in each of these methods shortly, but first we need to hook it up to the user interface in Interface Builder.
</li><br />
</ol>

<h2>Make The Interface Builder Connections</h2>

<p>Now that we&#8217;ve specified all of our actions and outlets in the <em>AppDelegate</em> code, let&#8217;s make the connections in our NIB file. To do so, use the following steps.</p>

<ol>
<li>In the tree view of your project in XCode, expand the smart folder labeled <em>NIB Files</em> and double click the file called <strong>MainMenu.nib</strong>

<em>Interface Builder</em> will load the NIB file.
</li>
<li>In <em>Interface Builder</em> click and drag an NSObject from the <em>Library</em> palette into your NIB file and rename the object to <strong>AppDelegate</strong> as shown:

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-4.png' title='Add App Delegate Object'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-4.thumbnail.png' alt='Add App Delegate Object' /></a></li>

<li>With the <strong>AppDelegate</strong> selected, select <strong>Tools > Inspector</strong> from the menu bar. In the inspector, select the <em>Object Identity</em> tab (tab 6) and in the <em>Class</em> field, enter <strong>AppDelegate</strong>.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-5.png' title='Set AppDelegate Object'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-5.thumbnail.png' alt='Set AppDelegate Object' /></a></li>

<li>Now we need to tell our application to use the <em>AppDelegate</em> object as its delegate. <em>Control-Click</em> on the <strong>File&#8217;s Owner</strong> object in the MainMenu.nib window and drag a connection to the <strong>AppDelegate</strong> object and select <strong>delegate</strong> in the ensuing pop-up menu.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-6.png' title='Set Delegate'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-6.thumbnail.png' alt='Set Delegate' /></a></li>

<li>All we have left now is to drag the controls onto the window and connect the actions and outlets. Edit the main window dragging controls to it so as to make it look like this.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-7.png' title='Main Window In Interface Builder'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-7.thumbnail.png' alt='Main Window In Interface Builder' /></a>

<strong>Note:</strong> The black area of the window is a <em>QTMovieView</em> which you&#8217;ll be able to find in the object library. It&#8217;s dimensions are set to a standard DV video format of 720 x 480 pixels.</li>

<li>Drag a connection (Control-Click) from the <em>Grab</em> button to the <em>AppDelegate</em> and select <strong>grab:</strong> from the dropdown.

 <a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-8.png' title='Connect Grab Button'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-8.thumbnail.png' alt='Connect Grab Button' /></a></li>

<li>Drag a connection from the <strong>File | Open&#8230;</strong> menu item to the <em>AppDelegate</em> and select <strong>openMovie:</strong> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-9.png' title='Connect Open Movie Menu'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-9.thumbnail.png' alt='Connect Open Movie Menu' /></a></li>

<li>Drag a connection from the <em>Select Output Folder Path</em> button to the <em>AppDelegate</em> and select <strong>selectOutputDir:</strong> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-11.png' title='Connect Select Output Folder Path Button'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-11.thumbnail.png' alt='Connect Select Output Folder Path Button' /></a></li>

<li>Drag a connection from the <em>AppDelegate</em> object to the Output Folder Path text field and select the <strong>outputPath</strong> <em>NSTextField</em> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-10.png' title='Connect AppDelegate To Output Path Textfield'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-10.thumbnail.png' alt='Connect AppDelegate To Output Path Textfield' /></a></li>

<li>Drag a connection from the <em>AppDelegate</em> object to the QTMovieView and select <strong>movieView</strong> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-13.png' title='Connect Movie View'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-13.thumbnail.png' alt='Connect Movie View' /></a></li>
</ol>

<p>Now we are finished in Interface Builder. Let&#8217;s return to XCode and start populating our event handlers with code. Don&#8217;t forget to save your NIB file in Interface Builder.</p>

<h2>Adding Event Handling Code</h2>

<p>For most of our event handlers, you can simply copy and paste the code from this section as their use is simply to set up the application and not directly related to the use of <em>NSOperation</em> or <em>NSOperationQueue</em>.</p>

<p><strong>- (void)awakeFromNib</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>awakeFromNib;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Initialize the queue</span>
    operationQueue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOperationQueue</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p><strong>- (IBAction)selectOutputDir:(id)sender;</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>selectOutputDir<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSOpenPanel</span> <span style="color: #002200;">*</span>openPanel;
&nbsp;
    openPanel <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOpenPanel</span> openPanel<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseDirectories<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setAllowsMultipleSelection<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setResolvesAliases<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseFiles<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>openPanel runModalForTypes<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span> <span style="color: #002200;">==</span> NSOKButton<span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>directory <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>openPanel directory<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>outputPath setStringValue<span style="color: #002200;">:</span>directory<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p><strong>- (void)dealloc</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc;
<span style="color: #002200;">&#123;</span>
    <span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> imagesMovie <span style="color: #002200;">&#41;</span>
        <span style="color: #002200;">&#91;</span>imagesMovie release<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>There are two other event handlers that we need to fill in, but they will require a little bit of explanation, so first let&#8217;s go and create our NSOpeation derived class that will do all of the work we need.</p>

<p><a name="derivedobject">&nbsp;</a></p>

<h2>Derive A Class From NSOperation</h2>

<p>In our application, we want to get the current image of the movie while it is playing back and save it out to disk. This is the operation that we want our NSOoperation to complete in a separate thread. In order to do this, we need to create a new Objective-C class that derives from NSOperation. To do so, complete the following steps.</p>

<ol>
<li>In the XCode treeview, Option-Click the <em>Classes</em> folder and select <strong>Add | New File&#8230;</strong>.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-12.png' title='Add New File'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-12.thumbnail.png' alt='Add New File' /></a>

In the ensuing dialog, select <strong>Objective-C Class</strong> and click next. Enter the name &#8216;GragQTImageOperation.m&#8217; making sure that <strong>Also create &#8220;GrabQTImageOperation.h&#8221;</strong> is checked and click <strong>Finish</strong></li>

<li>In the header file for the new Objective-C class you just created, change the interface so that our object inherits from NSOperation.


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@interface</span> GrabQTImageOperation <span style="color: #002200;">:</span> <span style="color: #400080;">NSOperation</span> <span style="color: #002200;">&#123;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>



</ol>

<h2>Give Our NSOperation Something To Do</h2>

<p>Our new class now needs some objects to work with and a method to do the work. To do work, an NSOperation derived class, must override the method called <strong>main:</strong>. Edit the file <em>GrabQTImageOperation.m</em> and provide the following function declaration.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main
<span style="color: #002200;">&#123;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>In order to do the work, we need the following objects:</p>

<ul>
<li><strong>QTMovie*</strong>: a pointer to a QTMovie view from which we will obtain our image to save.</li>
<li><strong>NSDictionary*</strong>: a dictionary to hold our attributes we will use when exporting to an image format</li>
<li><strong>NSLock*</strong>: a lock object to synchronize access to our QTMovie object.</li>
<li><strong>NSString*</strong>: a pointer to the output folder path we will use to save the files to.</li>
<li><strong>QTTime</strong>: a QTTime object representing the point in time as the movie was playing at which the grab button was clicked.</li>
</ul>

<p>Change the <em>GrabQTImageOperation</em> header file to look like this.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
<span style="color: #6e371a;">#import &lt;QTKit/QTKit.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> GrabQTImageOperation <span style="color: #002200;">:</span> <span style="color: #400080;">NSOperation</span> <span style="color: #002200;">&#123;</span>
    QTMovie<span style="color: #002200;">*</span> movie;
    <span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>imageAttrs;
    <span style="color: #400080;">NSLock</span> <span style="color: #002200;">*</span>lock;
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>outputPath;
    QTTime <span style="color: #a61390;">time</span>;
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>assign<span style="color: #002200;">&#41;</span> QTMovie <span style="color: #002200;">*</span>movie;
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>assign<span style="color: #002200;">&#41;</span> <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>outputPath;
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>assign<span style="color: #002200;">&#41;</span> QTTime <span style="color: #a61390;">time</span>;
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>saveImage<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>


<p>The method <strong>saveImage:</strong> actually saves the image to disk. Go ahead and add its declaration in the header as shown above. We&#8217;ll get back to that in a minute.</p>

<h2>Implement main:</h2>

<p>Now we need to switch to our implementation file (<strong>GrabQTImageOperation.m</strong>) and enter the following code into the <strong>main:</strong> function.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> movie <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span> image;
        <span style="color: #002200;">&#91;</span>lock lock<span style="color: #002200;">&#93;</span>;
        image <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>movie frameImageAtTime<span style="color: #002200;">:</span><span style="color: #a61390;">time</span> withAttributes<span style="color: #002200;">:</span>imageAttrs error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>lock unlock<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>self saveImage<span style="color: #002200;">:</span>image<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>All we are doing at this point is getting the image at the specified time from our QTMovie reference and passing it on to our <strong>saveImage:</strong> method. Now fill we can populate the rest of the methods with the code we need to finish our NSOperation derived class.</p>

<p><strong>- (id)init</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>init
<span style="color: #002200;">&#123;</span>
    lock <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSLock</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #11740a; font-style: italic;">// Specify that we want to save out a high-quality image.</span>
    imageAttrs <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>
                       QTMovieFrameImageTypeNSImage, QTMovieFrameImageType,
                       <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithBool<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>, QTMovieFrameImageHighQuality, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>imageAttrs retain<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>super init<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p><strong>- (void)saveImage:(NSImage*)image</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>saveImage<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>representations;
    <span style="color: #400080;">NSData</span> <span style="color: #002200;">*</span>bitmapData;
&nbsp;
    representations <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>image representations<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Specify that we want to save the file as a JPG</span>
    bitmapData <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBitmapImageRep</span> representationOfImageRepsInArray<span style="color: #002200;">:</span>representations 
                                usingType<span style="color: #002200;">:</span>NSJPEGFileType 
                                properties<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObject<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDecimalNumber</span> numberWithFloat<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#93;</span> 
                                forKey<span style="color: #002200;">:</span>NSImageCompressionFactor<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Creates a long filename, but at least it's unique.</span>
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>filename <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSProcessInfo</span> processInfo<span style="color: #002200;">&#93;</span> globallyUniqueString<span style="color: #002200;">&#93;</span>;
    filename <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>filename stringByAppendingString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;.jpg&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>imgOut <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>outputPath stringByAppendingString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;/&quot;</span><span style="color: #002200;">&#93;</span>;
    imgOut <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>imgOut stringByAppendingString<span style="color: #002200;">:</span>filename<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>bitmapData writeToFile<span style="color: #002200;">:</span>imgOut  atomically<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>And finally, don&#8217;t forget to add our synthesize calls at the top of the implementation.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> GrabQTImageOperation
&nbsp;
<span style="color: #a61390;">@synthesize</span> movie;
<span style="color: #a61390;">@synthesize</span> <span style="color: #a61390;">time</span>;
<span style="color: #a61390;">@synthesize</span> images;
<span style="color: #a61390;">@synthesize</span> outputPath;
...</pre></td></tr></table></div>


<h2>Finish Implementing AppDelegate</h2>

<p>Now that we&#8217;ve finished creating our <em>NSOperation</em> derived class, we can finish the implementation of our <em>AppDelegate</em>. First add the following code to the <strong>openMovie:</strong> event handler.</p>

<p><strong>- (IBAction)openMovie:(id)sender</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>openMovie<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSOpenPanel</span> <span style="color: #002200;">*</span>openPanel;
&nbsp;
    openPanel <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOpenPanel</span> openPanel<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseDirectories<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setAllowsMultipleSelection<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setResolvesAliases<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseFiles<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>openPanel runModalForTypes<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span> <span style="color: #002200;">==</span> NSOKButton<span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>filesToOpen <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>openPanel filenames<span style="color: #002200;">&#93;</span>;
        <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>theFilePath <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>filesToOpen objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>;
        QTMovie <span style="color: #002200;">*</span>movie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        imagesMovie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>imagesMovie retain<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>movieView setMovie<span style="color: #002200;">:</span>movie<span style="color: #002200;">&#93;</span>;		
    <span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Take note of these two lines:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;">QTMovie <span style="color: #002200;">*</span>movie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
imagesMovie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;</pre></td></tr></table></div>


<p>Notice that we are loading the same movie into memory twice. The first is for the object called <em>movie</em> which will be used in our <em>QTMovieView</em> for actual movie playback. The other movie is an instance variable called <em>imagesMovie</em> which will <em>act as a background movie</em>. It will be passed to our <em>NSOperation</em> derived class and it is the object from which the images will be obtained for saving to disk.</p>

<p>We use two movie objects representing the same file on disk in order to satisfy one of our requirements which was to ensure that the movie doesn&#8217;t flicker or stutter when the operation is happening. One movie reference is for display, the other for processing.</p>

<p>And finally, we now need to populate our <strong>grab:</strong> method which initializes our <em>NSOperation</em> derived objects and passes them off to the <em>NSOperationQueue</em> which runs them immediately. First, we need to import our header file at the top of <strong>AppDelegate.h</strong> like this:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;GrabQTImageOperation.h&quot;</span></pre></td></tr></table></div>


<p>And now, here is the implementation of <strong>grab:</strong> in <strong>AppDelegate.m</strong>.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>grab<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>path <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>outputPath stringValue<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">!</span>path || <span style="color: #002200;">&#91;</span>path length<span style="color: #002200;">&#93;</span> &lt;<span style="color: #002200;">=</span> <span style="color: #2400d9;">0</span> <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSAlert</span> <span style="color: #002200;">*</span>alert <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSAlert</span> alertWithMessageText<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Set Output Directory&quot;</span> defaultButton<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span> alternateButton<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span> otherButton<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span> informativeTextWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;You must first select an output directory before grabbing images.&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #002200;">&#91;</span>alert beginSheetModalForWindow<span style="color: #002200;">:</span>window
            modalDelegate<span style="color: #002200;">:</span>self
            didEndSelector<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span>
            contextInfo<span style="color: #002200;">:</span><span style="color: #a61390;">NULL</span><span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #a61390;">return</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Check to see if the movie is playing	</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>movieView movie<span style="color: #002200;">&#93;</span> rate<span style="color: #002200;">&#93;</span> &gt; 0.0f <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #11740a; font-style: italic;">// If so, create our NSOperation derived object and hand it off to the queue</span>
        GrabQTImageOperation <span style="color: #002200;">*</span>op <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>GrabQTImageOperation alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>op setMovie<span style="color: #002200;">:</span>imagesMovie<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>op setTime<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>movieView movie<span style="color: #002200;">&#93;</span> currentTime<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>op setOutputPath<span style="color: #002200;">:</span>path<span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #11740a; font-style: italic;">// As soon as this method finishes, the operation is set to work</span>
        <span style="color: #002200;">&#91;</span>operationQueue addOperation<span style="color: #002200;">:</span>op<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>The first thing we do is make sure our output path is set. If it is not, we alert the user and return. Otherwise, we check to see if our movie is playing by checking the movie&#8217;s current rate. If it is playing, then we are going to spin off one of our new <em>GrabQTImageOperation</em> objects to grab the image at the <em>currentTime</em>. Once we hand the image operation off to the <em>NSOperationQueue</em> we can watch the specified folder in the Finder and images will start to display.</p>

<p>To see the application run, click <strong>Build and Go</strong></p>

<h2>Conclusion</h2>

<p>Developing with <em>NSOperation</em> and <em>NSOperationQueue</em> is a very pleasant experience to me so far. This was a fun application to build and the results are quite pleasing. I was able to achieve all of my project requirements with very little effort. It&#8217;s a great addition to the toolset now available in OS X 10.5 Leopard.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/02/23/nsoperation-example/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Cocoa Tutorial: NSOperation and NSOperationQueue</title>
		<link>http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/</link>
		<comments>http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/#comments</comments>
		<pubDate>Sat, 16 Feb 2008 07:26:08 +0000</pubDate>
		<dc:creator>Marcus Zarra</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[NSOperation]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Threading]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/</guid>
		<description><![CDATA[Threading is hard in any language. And what is worse, when it goes wrong, it usually goes wrong in a very bad way. Because of this, programmers either avoid threading completely (and refer to it as the spawn of the devil) or spend a LOT of time making sure that everything is perfect. Fortunately, Apple [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.cimgf.com/wp-content/uploads/2008/02/light_bulb.png" alt="Light Bulb" align="left" style="margin: 5px;" />Threading is hard in any language.  And what is worse, when it goes wrong, it usually goes wrong in a very bad way.  Because of this, programmers either avoid threading completely (and refer to it as the spawn of the devil) or spend a LOT of time making sure that everything is perfect.</p>

<p>Fortunately, Apple has made a lot of progress in OS X 10.5 Leopard.  NSThread itself has received a number of very useful new methods that make threading easier.  In addition, they have introduced two new objects: NSOperation and NSOperationQueue.
<span id="more-4"></span>
In this Tutorial I will walk through a basic example that shows how to use these new Objects and how they make multi-threading your application nearly trivial.</p>

<blockquote>
You can get the example project here: <a href='http://www.cimgf.com/wp-content/uploads/2008/02/asyncdownloader.zip' title='Async Downloader Example Project'>Async Downloader Example Project</a>
</blockquote>

<p>In this tutorial, I will demonstrate one way in which to use NSOperation and NSOperationQueue to handle tasks that are best performed on background threads.  The intent of this tutorial is to demonstrate a basic use of these classes and is not intentioned to be the <em>only</em> way to use them.</p>

<p>If you are familiar with Java, or one of its variants, the NSOperation object is very similar to the java.lang.Runnable interface.  Like, in Java&#8217;s Runnable interface, the NSOperation object is designed to be extended.  Also like Java&#8217;s Runnable, there is a minimum of one method to override.  For NSOperation that method is -(void)main. One of the easiest ways to use an NSOperation is to load it into an NSOperationQueue.  As soon as the operation is loaded into the queue, the queue will kick it off and begin processing.  As soon as the operation is complete the queue will release it.</p>

<h2>NSOperation Example</h2>

<p>In this example, I have written an NSOperation that fetches a webpage as a string, parses it into an NSXMLDocument and then passes that NSXMLDocument back to the main thread in the application before completing.</p>

<p><strong>PageLoadOperation.h</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
&nbsp;
&nbsp;
<span style="color: #a61390;">@interface</span> PageLoadOperation <span style="color: #002200;">:</span> <span style="color: #400080;">NSOperation</span> <span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSURL</span> <span style="color: #002200;">*</span>targetURL;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>retain<span style="color: #002200;">&#41;</span> <span style="color: #400080;">NSURL</span> <span style="color: #002200;">*</span>targetURL;
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithURL<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSURL</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>url;
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>


<p><strong>PageLoadOperation.m</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;PageLoadOperation.h&quot;</span>
<span style="color: #6e371a;">#import &quot;AppDelegate.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> PageLoadOperation
&nbsp;
<span style="color: #a61390;">@synthesize</span> targetURL;
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithURL<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSURL</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>url;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>super init<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
    <span style="color: #002200;">&#91;</span>self setTargetURL<span style="color: #002200;">:</span>url<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc <span style="color: #002200;">&#123;</span>
    <span style="color: #002200;">&#91;</span>targetURL release<span style="color: #002200;">&#93;</span>, targetURL <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
    <span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main <span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>webpageString <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> alloc<span style="color: #002200;">&#93;</span> initWithContentsOfURL<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>self targetURL<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span> autorelease<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #400080;">NSError</span> <span style="color: #002200;">*</span>error <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
    <span style="color: #400080;">NSXMLDocument</span> <span style="color: #002200;">*</span>document <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSXMLDocument</span> alloc<span style="color: #002200;">&#93;</span> initWithXMLString<span style="color: #002200;">:</span>webpageString 
                                                              options<span style="color: #002200;">:</span>NSXMLDocumentTidyHTML 
                                                                error<span style="color: #002200;">:&amp;</span>error<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>document<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%s Error loading document (%@): %@&quot;</span>, _cmd, <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self targetURL<span style="color: #002200;">&#93;</span> absoluteString<span style="color: #002200;">&#93;</span>, error<span style="color: #002200;">&#41;</span>;
        <span style="color: #a61390;">return</span>;
    <span style="color: #002200;">&#125;</span>	
&nbsp;
    <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>AppDelegate shared<span style="color: #002200;">&#93;</span> performSelectorOnMainThread<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>pageLoaded<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span>
                                           withObject<span style="color: #002200;">:</span>document
                                        waitUntilDone<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>document release<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>


<p>As you can see, this class is very simple.  It accepts a URL in the init and stores it.  When the main method is called it constructs a string from the URL and then passes that string into the init of an NSXMLDocument. If there is no error with the loading of the xml document, it is then passed back to the AppDelegate, on the main thread, and the task is complete.  When the main method of the NSOperation ends the queue will automatically release the object.</p>

<p><strong>AppDelegate.h</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> AppDelegate <span style="color: #002200;">:</span> <span style="color: #400080;">NSObject</span> <span style="color: #002200;">&#123;</span>
	<span style="color: #400080;">NSOperationQueue</span> <span style="color: #002200;">*</span>queue;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>shared;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>pageLoaded<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSXMLDocument</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>document;
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>


<p><strong>AppDelegate.m</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;AppDelegate.h&quot;</span>
<span style="color: #6e371a;">#import &quot;PageLoadOperation.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AppDelegate
<span style="color: #a61390;">static</span> AppDelegate <span style="color: #002200;">*</span>shared;
<span style="color: #a61390;">static</span> <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>urlArray;
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>init
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>shared<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #002200;">&#91;</span>self autorelease<span style="color: #002200;">&#93;</span>;
        <span style="color: #a61390;">return</span> shared;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>super init<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
&nbsp;
    <span style="color: #400080;">NSMutableArray</span> <span style="color: #002200;">*</span>array <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableArray</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.google.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.apple.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.yahoo.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.zarrastudios.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.macosxhints.com&quot;</span><span style="color: #002200;">&#93;</span>;
    urlArray <span style="color: #002200;">=</span> array;
&nbsp;
    queue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOperationQueue</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    shared <span style="color: #002200;">=</span> self;
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>applicationDidFinishLaunching<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSNotification</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aNotification
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>urlString <span style="color: #a61390;">in</span> urlArray<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSURL</span> <span style="color: #002200;">*</span>url <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSURL</span> URLWithString<span style="color: #002200;">:</span>urlString<span style="color: #002200;">&#93;</span>;
        PageLoadOperation <span style="color: #002200;">*</span>plo <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>PageLoadOperation alloc<span style="color: #002200;">&#93;</span> initWithURL<span style="color: #002200;">:</span>url<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>queue addOperation<span style="color: #002200;">:</span>plo<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>plo release<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc
<span style="color: #002200;">&#123;</span>
    <span style="color: #002200;">&#91;</span>queue release<span style="color: #002200;">&#93;</span>, queue <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
    <span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>shared;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>shared<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>AppDelegate alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">return</span> shared;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>pageLoaded<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSXMLDocument</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>document;
<span style="color: #002200;">&#123;</span>
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%s Do something with the XMLDocument: %@&quot;</span>, _cmd, document<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>


<p>In this example AppDelegate, two things are occurring.  First, in the init method, the NSOperationQueue is being initialized and an array of urls is being loaded.  Then when the application has completed its load, the applicationDidFinishLaunching: method is called by the NSApplication instance and the AppDelegate loops over the urls, creating a task for each one and loading those tasks into the NSOperationQueue.  As soon as each item is loaded into the queue the queue will kick it off by assigning it to a NSThread and the thread will then run the main method of the operation.  Once the operation is complete the thread will report back to the queue and the queue will release the operation.</p>

<h2>NSOperationQueue Concurrency</h2>

<p>In this very simple example, it is quite difficult to load up the queue with enough objects to actually see it running them in parallel.  However, if you run tasks that take more time than these,  you will see that the queue will run all of the tasks at the same time.  Fortunately, if you want to limit how many tasks are running in parallel you can alter the init method in the App Delegate as follows:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>init
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>shared<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #002200;">&#91;</span>self autorelease<span style="color: #002200;">&#93;</span>;
        <span style="color: #a61390;">return</span> shared;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>super init<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
&nbsp;
    <span style="color: #400080;">NSMutableArray</span> <span style="color: #002200;">*</span>array <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableArray</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.google.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.apple.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.yahoo.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.zarrastudios.com&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>array addObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.macosxhints.com&quot;</span><span style="color: #002200;">&#93;</span>;
    urlArray <span style="color: #002200;">=</span> array;
    queue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOperationQueue</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>queue setMaxConcurrentOperationCount<span style="color: #002200;">:</span><span style="color: #2400d9;">2</span><span style="color: #002200;">&#93;</span>;
    shared <span style="color: #002200;">=</span> self;
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>In this updated init method, the queue is throttled down to 2 operations running at the same time.  The rest of the operations will wait until one of the first two is completed and then they will get an opportunity to run until the queue is empty.</p>

<h2>Conclusion</h2>

<p>That is the NSOperation and NSOperationQueue in its most basic form.  You will note that most of the code in this example has nothing to do with the building up or using of the NSOperation or the NSOperationQueue.  The actual code required to use the NSOperation is amazingly small.  Yet with this small amount of code you can easily start using multiple threads in your application and provide a better experience for the user and be able to fine tune those complicated tasks.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>
