<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	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/"
		>
<channel>
	<title>Comments on: imageNamed is evil</title>
	<atom:link href="http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/</link>
	<description>Alex Curylo, iPhone Programmer</description>
	<lastBuildDate>Tue, 16 Mar 2010 21:26:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-2/#comment-2903</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Mon, 01 Mar 2010 19:50:48 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2903</guid>
		<description>...get it going yes, but that doesn&#039;t mean it is going to work.  All the other stuff I am saying above is to give you some insight into where the pitfalls are.  For instance, you need to make sure your images are not too large for your animation duration.  If you are trying to animate 300x300 images at over 40 fps then you might run into trouble (particularly if you are also trying to manage user interactions with your animations).  This is just one of many problems that you might run into...some of the problems have solutions...some don&#039;t.  If your application requires you to do something that the iPhone just can&#039;t do (like, to exaggerate the point, you wanted to animate 300x300 images at 500 fps) then you won&#039;t be able to do it.  However, sometimes you can change your requirements a bit (like reduce the number of images you are trying to animate and thus cut your fps down to something more managable).  All of the other stuff above is stuff that might help you to work out how you might get around some of these issues.

What you can know for sure is that you must use imageNamed if you are going to be animating.  Short of that you have to figure out ways to get your images and code to balance between imageNamed sillyness and iPhone limitations (etc...).  I would also say that you are going to also need to do the animating with a timer like I have above.  Those are probably the two things you must do (imageNamed and timer).  So, make that your minimum application and try to make it fit in with your data.

Hope that helps...</description>
		<content:encoded><![CDATA[<p>&#8230;get it going yes, but that doesn&#8217;t mean it is going to work.  All the other stuff I am saying above is to give you some insight into where the pitfalls are.  For instance, you need to make sure your images are not too large for your animation duration.  If you are trying to animate 300&#215;300 images at over 40 fps then you might run into trouble (particularly if you are also trying to manage user interactions with your animations).  This is just one of many problems that you might run into&#8230;some of the problems have solutions&#8230;some don&#8217;t.  If your application requires you to do something that the iPhone just can&#8217;t do (like, to exaggerate the point, you wanted to animate 300&#215;300 images at 500 fps) then you won&#8217;t be able to do it.  However, sometimes you can change your requirements a bit (like reduce the number of images you are trying to animate and thus cut your fps down to something more managable).  All of the other stuff above is stuff that might help you to work out how you might get around some of these issues.</p>
<p>What you can know for sure is that you must use imageNamed if you are going to be animating.  Short of that you have to figure out ways to get your images and code to balance between imageNamed sillyness and iPhone limitations (etc&#8230;).  I would also say that you are going to also need to do the animating with a timer like I have above.  Those are probably the two things you must do (imageNamed and timer).  So, make that your minimum application and try to make it fit in with your data.</p>
<p>Hope that helps&#8230;</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-2/#comment-2902</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Mon, 01 Mar 2010 19:41:52 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2902</guid>
		<description>I typed more than I had too.  It is not as hard as appears from what I typed.  Put simply you need to create a subclass of a UIView.  And most everything you need to do will be in that subclass.  The iVars you will need will be your array of CGImageRefs, an integer called currFrame that tells drawRect which frame to draw during animation, and a timer to walk you through the animation.

The timer basically increments currFrame and causes the UIView to redraw itself (which means forces a call to drawRect).  drawRect is then called by the system and inside drawRect you draw whichever frame currFrame is pointing too (indexing).

Thus, each time the timer fires you get a new frame drawn and that is the animation.

All of the code is pretty much listed out for you in my mess of texts above, but in general it should be pretty simple to get it going....</description>
		<content:encoded><![CDATA[<p>I typed more than I had too.  It is not as hard as appears from what I typed.  Put simply you need to create a subclass of a UIView.  And most everything you need to do will be in that subclass.  The iVars you will need will be your array of CGImageRefs, an integer called currFrame that tells drawRect which frame to draw during animation, and a timer to walk you through the animation.</p>
<p>The timer basically increments currFrame and causes the UIView to redraw itself (which means forces a call to drawRect).  drawRect is then called by the system and inside drawRect you draw whichever frame currFrame is pointing too (indexing).</p>
<p>Thus, each time the timer fires you get a new frame drawn and that is the animation.</p>
<p>All of the code is pretty much listed out for you in my mess of texts above, but in general it should be pretty simple to get it going&#8230;.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Paul Squyres</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-2/#comment-2891</link>
		<dc:creator>Paul Squyres</dc:creator>
		<pubDate>Fri, 26 Feb 2010 04:52:50 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2891</guid>
		<description>Hey Daniel,

I really appreciate your help.  I am trying your code example with the timer and will let you know how it goes.  What you did makes sense, I just didn&#039;t know how to get started with it.  I hope this approach will work as I am getting tired and frustrated with it all.  Thanks Again!!!</description>
		<content:encoded><![CDATA[<p>Hey Daniel,</p>
<p>I really appreciate your help.  I am trying your code example with the timer and will let you know how it goes.  What you did makes sense, I just didn&#8217;t know how to get started with it.  I hope this approach will work as I am getting tired and frustrated with it all.  Thanks Again!!!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-2/#comment-2886</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Thu, 25 Feb 2010 04:52:57 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2886</guid>
		<description>Ok, that seemed to work.  So, just ignore that first coding post I did earlier. It doesn&#039;t make sense with all the lines missing.  Maybe it was just too long.  Hope that helps.</description>
		<content:encoded><![CDATA[<p>Ok, that seemed to work.  So, just ignore that first coding post I did earlier. It doesn&#8217;t make sense with all the lines missing.  Maybe it was just too long.  Hope that helps.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-2/#comment-2885</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Thu, 25 Feb 2010 04:51:31 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2885</guid>
		<description>Now, keep in mind that I think that you don&#039;t have to recreate the timer.  I think you could just create the timer once and simply put it on the run loop and invalidate it to remove it from the run loop.  But I can&#039;t remember so for this example I am just going to release it each time and recreate it.

So, here is the code to create the timer.

myThingyTimer = [[NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(myThingyTimerFired:) userInfo:nil repeats:YES] retain];
[[NSRunLoop currentRunLoop] addTimer:myThingyTimer forMode:NSDefaultRunLoopMode];

Just remember that you need to match up your timer release with this timer creation.  If you repeat this creation code then you will need to have done a release in between.

Ok, we are almost there.  The last thing we need to do is create a drawRect to put the images into our UIView.  That might look like this:

- (void) drawRect: (CGRect) aRect
{
	
  CGContextRef viewContext;	
		
  if ((currFrame &gt; 0) &amp;&amp; (currFrame &lt;= 185)) {
		
    viewContext = UIGraphicsGetCurrentContext();	
    CGContextTranslateCTM(viewContext, 0, self.bounds.size.height);
    CGContextScaleCTM(viewContext, 1.0, -1.0);
    CGContextDrawImage(viewContext, self.bounds, myThings[currFrame]);
  }
}

I think you need to flip the context so that the image doesn&#039;t get displayed backwards.  So, I put that in there with the translate and scale.  I can&#039;t remember exactly what that should be, but I think it is right.  If your images are showing up backwards or upside down then it is those two commands that is doing it.  Maybe comment them out or you could mess around with the values I used to get the image to be displayed properly.  I think it is right though.  Anyway, this will basically draw the image using the CGImageRef that you have in the myThings array at index currFrame.  This function is called each time the timer triggers because you have a [self setNeedsDisplay] in your timer fire function (myThingyTimerFired).  Also in the myThingyTimerFired function you increment currFrame so each time it triggers it advances to the next frame (image) in your animation.  And that should do it.

You have to forgive me any typos, and my memory is not perfect so I may have made some mistakes above.  I didn&#039;t get this from any code so it isn&#039;t tested or anything, but I think it should get you a good start.</description>
		<content:encoded><![CDATA[<p>Now, keep in mind that I think that you don&#8217;t have to recreate the timer.  I think you could just create the timer once and simply put it on the run loop and invalidate it to remove it from the run loop.  But I can&#8217;t remember so for this example I am just going to release it each time and recreate it.</p>
<p>So, here is the code to create the timer.</p>
<p>myThingyTimer = [[NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(myThingyTimerFired:) userInfo:nil repeats:YES] retain];<br />
[[NSRunLoop currentRunLoop] addTimer:myThingyTimer forMode:NSDefaultRunLoopMode];</p>
<p>Just remember that you need to match up your timer release with this timer creation.  If you repeat this creation code then you will need to have done a release in between.</p>
<p>Ok, we are almost there.  The last thing we need to do is create a drawRect to put the images into our UIView.  That might look like this:</p>
<p>- (void) drawRect: (CGRect) aRect<br />
{</p>
<p>  CGContextRef viewContext;	</p>
<p>  if ((currFrame &gt; 0) &amp;&amp; (currFrame &lt;= 185)) {</p>
<p>    viewContext = UIGraphicsGetCurrentContext();<br />
    CGContextTranslateCTM(viewContext, 0, self.bounds.size.height);<br />
    CGContextScaleCTM(viewContext, 1.0, -1.0);<br />
    CGContextDrawImage(viewContext, self.bounds, myThings[currFrame]);<br />
  }<br />
}</p>
<p>I think you need to flip the context so that the image doesn&#039;t get displayed backwards.  So, I put that in there with the translate and scale.  I can&#039;t remember exactly what that should be, but I think it is right.  If your images are showing up backwards or upside down then it is those two commands that is doing it.  Maybe comment them out or you could mess around with the values I used to get the image to be displayed properly.  I think it is right though.  Anyway, this will basically draw the image using the CGImageRef that you have in the myThings array at index currFrame.  This function is called each time the timer triggers because you have a [self setNeedsDisplay] in your timer fire function (myThingyTimerFired).  Also in the myThingyTimerFired function you increment currFrame so each time it triggers it advances to the next frame (image) in your animation.  And that should do it.</p>
<p>You have to forgive me any typos, and my memory is not perfect so I may have made some mistakes above.  I didn&#039;t get this from any code so it isn&#039;t tested or anything, but I think it should get you a good start.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-1/#comment-2884</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Thu, 25 Feb 2010 04:51:06 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2884</guid>
		<description>Anyway, back to the myThingyAnimationClass.  You will initialize currFrame to whichever frame you want to start at (probably 1).  And wherever you initialize currFrame you probably want to trigger a call to drawRect (we will talk about that below).  This is because you probably want your first frame to be displayed even though no animation is taking place yet.  If that is not the case then you need to initial currFrame to 0 so that the first frame will show up when the trigger is fired.

And that leaves us with two last things to deal with.  You need do draw a frame in drawRect and you need to trigger the call to drawRect (and the increment of currFrame) in a timer.  We already added a timer to our class iVars called myThingyTimer.  So, the first thing we need to do is to create a function to handle the timer.  We will call it myThingyTimerFired.  It might look something like this:

-(void) myThingyTimerFired:(NSTimer *)timer {
  currFrame = currFrame   1;
  if (currFrame &gt; 185) {
    currentFrame = 185;
				
    [myThingyTimer invalidate];
    //[myThingyTimer release];
  }
  else {
    [self setNeedsDisplay];
  }
}

This essentially walks through each of your frames and triggers drawRect.  When it reaches the last frame you will need to invalidate the timer.  Now, you have to create the timer somewhere and put it on the run loop.  This I can&#039;t remember off hand so I will look that code up.  I know the code, but I can&#039;t remember if you have to release the timer and recreate it every time or if you can just put it back on the run loop after it has been invalidated.  Oh heck, lets just release and recreate it each time.  So, you might add a [myThingyTimer release] to the myThingyTimerFired code above where I put it in comments.  Now, that depends on how you are doing things in your code.  Basically you will need to invalidate and release the timer before you recreate it.  In other words, lets say you want to have an animation occur ever time the user touches the UIView.  So, each time the user touches the UIView you will create a new timer.  After the animation completes you will need to invalidate and release the timer so that it could be recreated for the next time the user touches the UIView.  Where that is done is a question that relates to what you are doing in your code.</description>
		<content:encoded><![CDATA[<p>Anyway, back to the myThingyAnimationClass.  You will initialize currFrame to whichever frame you want to start at (probably 1).  And wherever you initialize currFrame you probably want to trigger a call to drawRect (we will talk about that below).  This is because you probably want your first frame to be displayed even though no animation is taking place yet.  If that is not the case then you need to initial currFrame to 0 so that the first frame will show up when the trigger is fired.</p>
<p>And that leaves us with two last things to deal with.  You need do draw a frame in drawRect and you need to trigger the call to drawRect (and the increment of currFrame) in a timer.  We already added a timer to our class iVars called myThingyTimer.  So, the first thing we need to do is to create a function to handle the timer.  We will call it myThingyTimerFired.  It might look something like this:</p>
<p>-(void) myThingyTimerFired:(NSTimer *)timer {<br />
  currFrame = currFrame   1;<br />
  if (currFrame &gt; 185) {<br />
    currentFrame = 185;</p>
<p>    [myThingyTimer invalidate];<br />
    //[myThingyTimer release];<br />
  }<br />
  else {<br />
    [self setNeedsDisplay];<br />
  }<br />
}</p>
<p>This essentially walks through each of your frames and triggers drawRect.  When it reaches the last frame you will need to invalidate the timer.  Now, you have to create the timer somewhere and put it on the run loop.  This I can&#8217;t remember off hand so I will look that code up.  I know the code, but I can&#8217;t remember if you have to release the timer and recreate it every time or if you can just put it back on the run loop after it has been invalidated.  Oh heck, lets just release and recreate it each time.  So, you might add a [myThingyTimer release] to the myThingyTimerFired code above where I put it in comments.  Now, that depends on how you are doing things in your code.  Basically you will need to invalidate and release the timer before you recreate it.  In other words, lets say you want to have an animation occur ever time the user touches the UIView.  So, each time the user touches the UIView you will create a new timer.  After the animation completes you will need to invalidate and release the timer so that it could be recreated for the next time the user touches the UIView.  Where that is done is a question that relates to what you are doing in your code.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-1/#comment-2883</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Thu, 25 Feb 2010 04:50:19 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2883</guid>
		<description>Ok, so far the only iVar you need is the CGImageRef array, but you will also need some indicator of what frame you are animating.  Let call it currFrame.  And you will need some timer (we will talk about that shortly).  So, your class definition will look something like this:

@interface myThingyAnimationClass : UIView
{
  CGImageRef myThings[185];
  int currFrame;
  NSTimer *myThingyTimer;
}
//put whatever methods you create here
@end

Note that everything I am talking about so far will be contained in the implementation of this myThingyAnimationClass.  The only thing outside this class for our simple example would be creating an instance of the myThingyAnimationClass and putting it as a subview of some other parent view (or whatever).  And I should repeat at the time of the creation of that instance you will give this myThingyAnimationClass a frame that must be the same size as the actual dimensions of your images (it doesn&#039;t have to be, but if it is not then you might experience some slowness to your animation due to the resizing of the images).  This is worth repeating as it can be substantial.</description>
		<content:encoded><![CDATA[<p>Ok, so far the only iVar you need is the CGImageRef array, but you will also need some indicator of what frame you are animating.  Let call it currFrame.  And you will need some timer (we will talk about that shortly).  So, your class definition will look something like this:</p>
<p>@interface myThingyAnimationClass : UIView<br />
{<br />
  CGImageRef myThings[185];<br />
  int currFrame;<br />
  NSTimer *myThingyTimer;<br />
}<br />
//put whatever methods you create here<br />
@end</p>
<p>Note that everything I am talking about so far will be contained in the implementation of this myThingyAnimationClass.  The only thing outside this class for our simple example would be creating an instance of the myThingyAnimationClass and putting it as a subview of some other parent view (or whatever).  And I should repeat at the time of the creation of that instance you will give this myThingyAnimationClass a frame that must be the same size as the actual dimensions of your images (it doesn&#8217;t have to be, but if it is not then you might experience some slowness to your animation due to the resizing of the images).  This is worth repeating as it can be substantial.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-1/#comment-2882</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Thu, 25 Feb 2010 04:49:29 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2882</guid>
		<description>Ok, first thing you will need to do is to load your images.  I would load them into an common C array of CGImageRefs.  Like this:

for (int i=1; i&lt;=185; i  ) {
  NSString *cname = [NSString stringWithFormat:@&quot;d.png&quot;, i];
  UIImage *img = [UIImage imageNamed:cname];
  myThings[i] = CGImageRetain(img.CGImage);
}

This assumes that your filenames are 3 digit png&#039;s (like 001.png, 002.png, … 185.png) and that all of the images are loaded into your app (there is some trickiness here in getting them loaded so that imageNamed finds them without having to reference them with the entire path, but usually it will default to the proper settings.  If your images come up all black then that is because imageNamed is not finding them in the path.

Ok, so that should load your CGImageRefs into the myThings array.  Remember that somewhere in your code you will need to release those references.  Something like this:

for (int i=1; i&lt;=185; i  ) {
  CGImageRelease(myThings[i]);
}

Where you do this depends on whether you are switching out the 185 images for another set of 185 images.  If you are just keeping them in memory for the running of your app then you would do this in the dealloc, but you need to do it somewhere.</description>
		<content:encoded><![CDATA[<p>Ok, first thing you will need to do is to load your images.  I would load them into an common C array of CGImageRefs.  Like this:</p>
<p>for (int i=1; i&lt;=185; i  ) {<br />
  NSString *cname = [NSString stringWithFormat:@&quot;d.png&quot;, i];<br />
  UIImage *img = [UIImage imageNamed:cname];<br />
  myThings[i] = CGImageRetain(img.CGImage);<br />
}</p>
<p>This assumes that your filenames are 3 digit png&#039;s (like 001.png, 002.png, … 185.png) and that all of the images are loaded into your app (there is some trickiness here in getting them loaded so that imageNamed finds them without having to reference them with the entire path, but usually it will default to the proper settings.  If your images come up all black then that is because imageNamed is not finding them in the path.</p>
<p>Ok, so that should load your CGImageRefs into the myThings array.  Remember that somewhere in your code you will need to release those references.  Something like this:</p>
<p>for (int i=1; i&lt;=185; i  ) {<br />
  CGImageRelease(myThings[i]);<br />
}</p>
<p>Where you do this depends on whether you are switching out the 185 images for another set of 185 images.  If you are just keeping them in memory for the running of your app then you would do this in the dealloc, but you need to do it somewhere.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-1/#comment-2881</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Thu, 25 Feb 2010 04:49:06 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2881</guid>
		<description>It won&#039;t let me repost.  Very strange.  Let me break it up.</description>
		<content:encoded><![CDATA[<p>It won&#8217;t let me repost.  Very strange.  Let me break it up.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daniel Alexander</title>
		<link>http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/comment-page-1/#comment-2880</link>
		<dc:creator>Daniel Alexander</dc:creator>
		<pubDate>Thu, 25 Feb 2010 04:44:53 +0000</pubDate>
		<guid isPermaLink="false">http://www.alexcurylo.com/blog/?p=386#comment-2880</guid>
		<description>Hey, part of my messages are being chopped out. Like lots of my code message is lost.  I&#039;m not sure why that is.  Let me try to post it again....here goes....</description>
		<content:encoded><![CDATA[<p>Hey, part of my messages are being chopped out. Like lots of my code message is lost.  I&#8217;m not sure why that is.  Let me try to post it again&#8230;.here goes&#8230;.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
