Animating Graphics in Cocoa, Part 1
Pages: 1, 2, 3, 4, 5
Multithreading
This annoying behavior is a side effect of our application having only one thread of execution. That is, only one thing can happen at a time, and the consequence is that when the control is being held and moved, the animation timer stops temporarily until we release the control. To fix this, we make our application multithreaded. The way this works is that when AnimationView is initialized, we detach a new thread from the main thread of execution. In the new thread, we handle the animation loop, and in the main thread we handle any user interaction. By doing this, we can create a much nicer animation and user interaction experience.
A new thread is created using the class method of NSThread +detachNewThreadSelector:toTarget:withObject:. This method takes as its arguments a selector to be invoked -— the method we want to execute in the new thread -- the target of the method indicated by the selector, and some object that contains arbitrary information we might want to access in the new thread. Note that threads are set up to execute a single method.
We’ll detach a new thread in the initialization code of initWithFrame:. The line creating a new thread will replace the code where we previously created our timer.
[NSThread detachNewThreadSelector:@selector(animate:) toTarget:self withObject:nil];
The thread we are creating here will execute a method called animate:, of the class AnimationView. The withObject: argument is nil since there is nothing we want to communicate with the new thread. The method -animate: is new to us; it will contain the code necessary to kick off and time the animation.
When we make a new thread, the first thing that must happen is the creation of an autorelease pool, and the last thing that the thread does before exiting is to release this pool. Until now, we’ve never had a need to create our own autorelease pool. Cocoa has always supplied one for us. Note that if you are using a thread to execute code that doesn’t use the Cocoa frameworks, then you don’t need to create and autorelease pool.
For example, if you had a method that ran some lengthy calculation using only the standard C math functions, then you wouldn’t need an autorelease pool. With this new context for using autorelease pools, you might want to review that documentation. With this, let's set up the framework for the method animate::
- (void)animate:(id)anObject
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// execute our code here
[pool release];
}
The argument to animate: is type id; this is the way a method must be set up for use by a thread. The object we specify in withObject: when we create a new thread is passed as an argument to animate:, and we can access it thusly. For more information about NSThread, take a gander through the class reference; it’s pretty short and straight to the point, with many useful insights about threads.
Our animation code is sandwiched between the two lines dealing with the autorelease pool. Lets take a look at that now.
Multithreaded Animation
When we use a separate thread for the animation timing, we’re going to do things a bit differently than above. Rather than use a timer that fires whenever we want a new frame, we will set up a continuous while statement that steps the animation. Within the while loop we will do two things: we will call stepAnimation, and we will tell the display to update itself. –animate: looks like this:
- (void)animate:(id)anObject
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
while (YES) {
[self stepAnimation:nil];
[self setNeedsDisplay:YES];
}
[pool release];
}
Note that -stepAnimation: also calls setNeedsDisplay:. We want to delete that line from stepAnimation:, since it is now called in the while loop of animate:. The reason we moved it is purely a matter of that message “fitting” in better with the function of –animate: as opposed to –stepAnimation:.
If you run this code as is, you will notice another disturbing behavior: the ball is just jumping all over the place —- nothing nice about that. The reason for this is that when we call [self setNeedsDisplay:YES] the display is not immediately updated. The main thread of execution deals with drawing via drawRect: when it gets some processor time; all we do is let the view know we want an update.
However, while the main thread wants to draw, the animation thread is looping through that while statement as fast as it can, and the main thread tries to update as soon as it can, but it simply can’t keep up. As a result, the animation progresses many more steps between each redraw. To remedy this problem, we tell the animation thread to take a break for a short while and let the other thread take care of business. This is accomplished using the NSThread method sleepUntilDate: after we call for an update to the display:
- (void)animate:(id)anObject
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
while (YES) {
[self stepAnimation:nil];
[self setNeedsDisplay:YES];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.04]];
}
[pool release];
[NSThread exit];
}
|
Also in Programming with Cocoa |
Notice we choose the time interval to be the same as the NSTimer interval we had earlier. With this, you can run the animation and everything will look good. Notice that you can now move the sliders and the speed of the ball will change in real time -- no annoying pause. And that is one of the uses of multithreading: sending some code off to do its thing without locking the user out of the application.
As you’ll read in the NSThread reference, be careful about your multithreading, because when you get down to it, the processor really can only do one thing at a time. The real benefit of multithreading comes when you have multiple processors. Then you can really execute two or more things simultaneously.
The End
We have seen how we can do some pretty good multithreaded animation that lets the user interact with what's going on. The link to download the first version of this application was given above. The project folder for the second version can be downloaded here and finally, here is a link to a third project that works the animation in a slightly different way, allowing the user to scale the size of the ball. I leave you with that to ponder.
Michael Beam is a software engineer in the energy industry specializing in seismic application development on Linux with C++ and Qt. He lives in Houston, Texas with his wife and son.
Return to the Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 40 of 40.
-
if (self)
2003-11-11 14:26:11 anonymous2 [Reply | View]
could someone tell me what the conditional if (self) means. i understand what self means but i don't understand how you can have a condition with no relational operator. thats like saying if (x) and that doesn't make sense to me. thanks in advance.
-
Animating an NSImageView
2003-04-28 09:42:37 anonymous2 [Reply | View]
Speaking of animation. I am trying to move an NSImageView around a window. I can do that, but I have problems with leaving portions of the View behind. Is there some trick to move the View without these reminants? I was thinking about hiding the view, moving it, then redisplaying it, but I don't see a method to hide an NSImageView.
-
Memory leak
2003-03-26 18:05:02 anonymous2 [Reply | View]
This example contains a memory leak.
Each iteration of the animation creates a new NSDate object that is never released.
Something like this is requires:
NSDate *run_time;
run_time = [NSDate dateWithTimeIntervalSinceNow:0.04];
[NSThread sleepUntilDate:run_time];
[Run_time release];
-
Memory leak
2003-08-22 15:18:45 anonymous2 [Reply | View]
I'm not an expert, but I think this is not right. I tried it, and adding the release message makes everything crash after the loop ends. I think that dateWithTimeIntervalSince must be creating an already autoreleased object, no? -
Memory leak
2005-07-29 18:28:09 valiantsoul [Reply | View]
Thats correct, watch NSCFDate in ObjectAlloc while the program is running - it gets called all the time but the peak amount of times an object of that type exists is 1 meaning no leak. -
Memory leak
2005-07-29 18:39:01 valiantsoul [Reply | View]
Oops sorry I forgot to watch CFDate and yes there is a memory leak.
Here is my modified animate: with no leak:
- (void)animate:(id)anObject
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDate *date = nil;
while (YES)
{
[self stepAnimation:nil];
[self setNeedsDisplay:YES];
if (date != nil)
[date release];
date = [NSDate dateWithTimeIntervalSinceNow:0.04];
[NSThread sleepUntilDate:date];
}
[pool release];
[NSThread exit];
}
-
Faulty collision method
2003-01-24 07:05:03 anonymous2 [Reply | View]
The collision method given will not handle corner-collisions correctly. If both x & y coordinates are out of the bounds, the checkCollision method will only flip the y coordinate: this is due to the use of if... else if rather than two ifs.
In most cases, this won't be a problem, as most collisions will not occur at the corners. However, if the collision does occur at a corner, only delta y will be flipped.
This will result in the x-coordinate of the ball to be outside the intended display bounds. Because the x-coordinate is incremented even though it should have been flipped, the ball is moved further from the intended view area. After this, the ball's x position will be stuck until the next y-collision, (or possibly longer) which is not the desired effect.
New version:
- (void)checkCollision
{
NSRect ballRect = [ball bounds];
NSRect viewRect = [self bounds];
BOOL flipY = ( ballRect.origin.y < viewRect.origin.y || (ballRect.origin.y + ballRect.size.height) > viewRect.size.height );
BOOL flipX = ( ballRect.origin.x < viewRect.origin.x || (ballRect.origin.x + ballRect.size.width) > viewRect.size.width );
if ( flipY || flipX ) { //If we need to flip one of the coords,
[at release];
at = [[NSAffineTransform transform] retain];
if ( flipY ) //Flip coordinates as needed.
dy = -dy;
if ( flipX )
dx = -dx;
[at translateXBy:dx yBy:dy];
}
}
(Think that one will work.... Still, if the view is resized and the ball is outside of the new bounds, it'll stay out there.)
Of course, this is a simple tutorial, and it's not really important. But I though I'd point it out.
Peace, Nicholas Seckar
-
Memory leak??
2002-06-01 10:26:14 chask [Reply | View]
When running the animation program through ObjectAlloc, the number of current NSBezierPath objects keeps increasing as long as the program is running. Is this a memory leak? And, if so, what can be done to avoid it?
-
Archiving graphics
2002-01-17 11:11:10 michele [Reply | View]
Hello Mike,
It is not exactly related to this article, but well, for the first time in my life I really enjoy graphics coding (thanks to you).
My question: I have a small programm which draws bezier paths in different locations, sizes, colors and line widths.
Bezier paths, colors and line widths are managed as arrays.
I know how to archive and unarchive one array with one NSData object. How do I archive three arrays with one NSData object?
Any hint would be much appreciated,
Michèle -
Archiving example
2002-01-19 00:11:28 psheldon [Reply | View]
I think NSArray holds any sort of object, including arrays. ADC might have said this to you. I wanted to write on the animation 1 thread before you started looking at the new thread and missed it.
http://www.oreillynet.com/pub/ct/37
lists all the columns Mike wrote. You seem to have come in late and maybe missed one of the columns.
I've read and programmed from every one, but still feel like a newby. I think it is getting easier to read a column and lingo gets more and more familiar, so I am learning something.
When cocoa first came out, I ventured out on my own alot thinking I could somehow debug immature early documentation and make it grow strong. It was confusing and now I wait for Mike's column but sometimes catch fire with a solo attempt again. The last four days I've gotten dizzy with Maple problem wherein I caught fire.
On the above list of columns, is a link to an address book which, I recall, showed a number of ways to save stuff.
First to build the address book :
http://www.oreillynet.com/pub/a/mac/2001/08/10/cocoa.html
Next to save it various ways :
http://www.oreillynet.com/pub/a/mac/2001/08/24/cocoa.html
Perhaps, in your having struggled with saving graphics, this will firm up the memories for you. Remember, life will have you revisit useful stuff and then you'll be able to relearn it faster than you originally learned it.
;-) -
Archiving graphics
2002-01-18 14:47:49 michele [Reply | View]
Hello Mike,
Thanks to nice guys at cocoa-dev mailing list and after a whole day tracking memory leaks, archiving and unarchiving works almost fine with an NSMutableDictionary.
Saving and opening works fine, but closing the window calls the save panel only when an IBAction occured (changing colors and line widths).
I still don't know how to tell the document that the view has changed after a mouse event has occured (paths are drawn by defining a rectangle from mouse down, mouse dragged, and mouse up events).
Any idea?
Thanks in advance,
Michèle
-
Archiving graphics
2002-01-20 11:17:34 Michael Beam |
[Reply | View]
you might want to look into converting this application into a document based application. When you say you "don't know how to tell the document that the view has changed after a mouse event has occured" do you mean to tell the document to redraw itself or to not let you close the document without asking you to save unsaved changes?
For your other question in the previous post i would have gone the route you did with the NSMutableDictionary.
Mike -
Archiving graphics
2002-01-20 14:29:24 michele [Reply | View]
Hello Mike,
I mean not let me close the document without asking me to save unsaved changes.
I've already converted the application into a document based application, added synchronisation between colors (background and brush) and color wells as well as line width and line width slider on opening a document.
It works fine as long as I don't close the window or quit the application without closing a changed document.
Thanks for your help,
Michèle
-
Archiving graphics
2002-01-23 21:08:29 Michael Beam |
[Reply | View]
Ah, i see. You want to tell the document that you've made a change to something important and it shouldn't let you close the document window without providing some feedback that there are unsaved changes. This is actually pretty easy.
When you modify the document's data (I'm assuming the code that does this is in your NSDocument subclass) you want to use the NSDocument method
-updateChangeCount:. The argument to this is one of three constants: NSChangeDone, NSChangeUndone, and NSChangeCleared. So, in your method that modifies your data you would want to have executed is:
[self updateChangeCount:NSChangeDone];
This will mark your document as having unsaved changes. The reason for the complexity of this is to support the undo system. I hope i answered the correct question and that the answer was helpful.
BTW, i'm working on the your question about the tablecolumn thing from several, several columns ago. I think a future column will cover it, but if you want to know what i'm thinking feel free to email me and i'll share with you. Talk to you later!
Mike
-
Animating several balls
2002-01-15 06:50:16 destanley [Reply | View]
Wow! Great. This is exactly the kind of stuff I'm interested in. Now if Mike can only attack video and sound (hint hint).
Anyway, I tweaked the exercises in order to better understand Cocoa animation, had a lot of fun, and hit a wall when trying to animate several balls. I think the question is: how should I attack things in Cocoa from an object-oriented viewpoint. I'm a procedural kind of guy and I'm having problems figuring out exactly when to subclass, what to subclass and where (in a view, in an NSObject, etc), when to make my own classes, and when to use Apple's. I really get all the Model-Controller-View stuff theoretically, but I don't see it really in action here.
It seemed to me the most logical thing would be to make several "ball" objects, each one containing 'dx', 'dy', their NSBezierPath and their own NSAffineTransform. Then an array (mutable just for fun) would hold all those objects and some controller object would allow you to affect their dx and dy values while they looped, drawing themselves so to speak.
Well, the problem is of course that there is only one NSView while there are several objects, and... well you see... I still haven't fully *gotten* Cocoa...
-
Animating several balls
2002-01-20 11:12:41 Michael Beam |
[Reply | View]
Yeah, animating several balls is a problem that i've not yet tackled. Your proposed solution is often the one pops into my head when i think about it. Instead of having a controller object alter their values of dx and dy you caould have the custom view take care of that. At each animation step the view could tell each ball in the array (via an enumerator) to move forward a step, and then in the drawRect method you could again enumerate your array of balls and send -draw messages to each ball which would tell them to draw themselves. Something along those lines.
If you're interested in learning more about how to build objects, when to build them, what they should be, what should be subclassed, etc. you should look into Design Patterns (the book), and more generally design patterns the concept.
You should approve of the next column :-)
-
For smoother control at particular times
2002-01-12 21:56:21 psheldon [Reply | View]
Current value of slider in IB should match initialization for smooth control at beginning.
Maybe slider control could have some sort of callback when things are away from the walls? I didn't understand callbacks on the newton.
I'm dizzy that's as good as it gets tonight.
;-)
-
on the use of words "of course" to Socrates
2002-01-12 21:34:50 psheldon [Reply | View]
I tried putting in para's to insure paragraphs.
para
I was terrified of a math professor once who would loudly intone each time he saw in a publication the words "of course" or "easy to prove" the hostile remark, "Well if it was so easy to prove, why didn't he spell it out". He would "play Socrates" and drive argument not coming from solid formal reasoning from either axiom or definition into the ground. He might have died reading Poincare, "Science and the Nature of Hypothesis". Me, I read half of it and then I went skiing. I mercifully never told him of this reading material.
para
Whenever I see those words, I imagine that easily believing it might lead to him meeting me in some dim hallway somewhere and disproving my very existance. However, maybe I can glean some pivotal idea about how to react to these words in a somewhat less hostile and more hopeful fashion.
para
Mike writes : "The receiver is, of course, animationView, the outlet to the view container, AnimationView. Simple as that." bottom my p.9 of my pdf ified printout.
para
Context is helping me see how outlets work. There was some abstract writing about this somewhere which I dutifully read but rapidly forgot because I hadn't "gone through pain". I do need your heuristic context introduction to somewhat painfully motivate me for remembering or even better writing the formal abstract writing.
para
I believe we might make the generality that the words "of course" always will indicate this human ambivalence. Perhaps there are other ways to write that "cover" this ambivalent feeling, though covering it too well may hurt the motivational aspect. -
on the use of words "of course" to Socrates
2002-01-20 11:23:38 Michael Beam |
[Reply | View]
everytime i write the words "of course" or "obviously" i pause and hesistate about whether i should say something that way. A friend of mine and I had a discussion about this and how he hated it when professors say "obviously" or "of course", b/c it may not be obvious to someone, and it just serves to make them terrified to ask. I suppose i should just eliminate those words from my vocabulary, as it is not my intent to make someone feel uncomfortable for not realizing something. I'm the last person who should be telling another that something is obvious or plain to see when i often need to be told of someting sitting right in front of my face. So, obviously, my point is that "obviously" and "of course" are out :-)
-
(Q) NSTimer timer unneeded
2002-01-12 21:02:32 psheldon [Reply | View]
Forgive this bit of mindreading, perhaps we might benefit reading our own minds this way
and something obscure about assignments might manifest itself that will help us all program :
NSTimer timer assignment superfluous, as address registered in some sort of loop by method, but syntactically necessary. Later you take it out of the initialization method, since it is not used there and you assumed it, incorrectly, global. Rather, the variable pointing to the address had no semantic use anywhere!
Is this "insight" correct? Is it useful? -
(Q) NSTimer timer unneeded
2002-01-20 11:25:29 Michael Beam |
[Reply | View]
You're mindreading is indeed correct, and i came to this realization too when writing this column. I guess old habits die hard. Who knows why i kept putting the NSTImer variable assignment in there. Oh well :-) -
NSTimer timer unneeded, speculation on losing balls
2002-01-13 15:47:29 psheldon [Reply | View]
NSThread said that communication, careful communication, between threads was possible. Right now, StepAnimation takes an argument of nil. What if I made timer, not a local method variable, but rather an instance variable of NSView? And what if I had StepAnimation take it as an argument?
I have to go dancing now, but maybe someone out there would try this (dangerous?) interthread communication. I think, with protected memory, I shall try it later tonight somewhat fearlessly. -
it didn't bomb
2002-01-13 22:33:09 psheldon [Reply | View]
Nor did it make much sense. Here's why :
1. I think the idea of the timer is that it is like a sender that fires off the method, but I see it isn't used, like a time, in the method. So, if I call stepAnimation with it as an argument, I, not it, called stepAnimation which isn't going to wait for it.
2. We didn't want it to wait for more interactive controls, so the idea was a bit crazy there too.
I think I was tempted, by some communication between threads, to get some sort of foggy low level analogy of Everett phones working between parallel timelines. My idea was to suspend disbelief until I had a chance to get a handle on some ideas and make them "coherent".
This still lost the balls if I moved the sliders when ball near edge.
-
Question on NSDictionary
2002-01-07 02:39:53 michele [Reply | View]
Hello Mike,
This is not a question about this article, but about an older one, as I'm not sure you have time to deep into older artiicles to see if there is new comments.
At the end of the Adding a Preferences Window, you told us to enhance the code with an array of dictionaries and that you'll give us the solution in next article. I must admit I can get the way to do it and did not see any solution in further articles.
Could you manage time to do it, please. It would be a great help for me.
Thanks in advance,
Michèle
-
Question on NSDictionary
2002-01-09 11:39:42 Michael Beam |
[Reply | View]
If you give me some time to dig that up i'll try and get some code posted that shows how this is done.
Mike
-
Some changes and questions
2002-01-07 02:30:53 michele [Reply | View]
Hello Mike,
I propose some changes to explanation and code, I have some question too.
First of all, we need to change slightly the code for bouncing since as it is built it appends within special conditions that the ball runs out of the view.
In fact, if the ball moves up when the user changes the speed of the ball and the bottom edge of the ball is already under the bottom edge of the view, inverting the translation means the ball goes further down, which is not what we intend to do. And this happens because of the delay.
Furthermore, we need it dramatically when we apply the scale transform.
New code in the first and second projects:
- (void)checkCollision
{
NSRect ballRect = [ball bounds];
NSRect viewRect = [self bounds];
// Bottom edge of the ball is below bottom edge of the view and translation is negative or
// top edge of the ball is above top edge of the view and translation is positive
if (((ballRect.origin.y < viewRect.origin.y) && dy < 0) ||
(((ballRect.origin.y + ballRect.size.height) > viewRect.size.height) && dy > 0))
{
// Inverse the translation
dy = - dy;
[at release];
at = [[NSAffineTransform transform] retain];
[at translateXBy:dx yBy:dy];
}
// left edge of the ball is left to left edge of the view and translation negative or
// right edge of the ball is right to right edge of the view and translation is positive
else if (((ballRect.origin.x < viewRect.origin.x) && dx < 0) ||
(((ballRect.origin.x + ballRect.size.width) > viewRect.size.width) && dx > 0))
{
// Inverse the translation
dx = - dx;
[at release];
at = [[NSAffineTransform transform] retain];
[at translateXBy:dx yBy:dy];
}
}
Change in the third project:
- (void)checkCollision
{
NSRect ballRect = [drawnBall bounds];
NSRect viewRect = [self bounds];
// Bottom edge of the ball is below bottom edge of the view and translation is negative or
// top edge of the ball is above top edge of the view and translation is positive
if (((ballRect.origin.y < viewRect.origin.y) && dy < 0) ||
(((ballRect.origin.y + ballRect.size.height) > viewRect.size.height) && dy > 0))
{
// Inverse the translation
dy = - dy;
}
// left edge of the ball is left to left edge of the view and translation negative or
// right edge of the ball is right to right edge of the view and translation is positive
else if (((ballRect.origin.x < viewRect.origin.x) && dx < 0) ||
(((ballRect.origin.x + ballRect.size.width) > viewRect.size.width) && dx > 0))
{
// Inverse the translation
dx = - dx;
}
}
Then, we need to #import "AnimationView.h" into AnimationController.m in second and third project in order to avoid build warnings.
Third, in the explanation, in Multithreaded Animation part, first paragraph, the code must be:
- (void) animate: (id) anObject
{
....
[self setNeedsDisplay: YES];
...
}
instead of setNeedsDisply: YES], pretty obvious, but when copying...
Fourth, is [NSThread exit] needed at the end of the animate function? It appears in the explanation, Multithreaded Animation part, fourth paragraph, but disappears in code.
Fifth, the animate function is slightly different between second and third project: change in the order of calls into while loop. I wonder if it is important.
In second project:
while (YES)
{
[self stepAnimation:nil];
[self setNeedsDisplay:YES];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.04]];
}
and in third project:
while (YES)
{
[self stepAnimation:nil];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.04]];
[self setNeedsDisplay:YES];
}
Seems to me that the second one is better.
I've added some code to dealloc too:
- (void) dealloc
{
[at release];
[st release]; // only in third project
[ball release];
[drawnBall release]; // only in third project
[super dealloc];
}
Hope, I've not omitted some object.
Could you, please, correct me if I'm wrong and go into further details about exiting the thread.
And many thanks for your explanation. I was completely lost at the end of Learning Cocoa book and your tutorial gave me enough energy to go on.
Michèle
-
thanks #import "AnimationView.h", other insights
2002-01-12 21:16:25 psheldon [Reply | View]
I got warnings and it made me doubt I knew what was going on with containers.
I've attempted to write something pivotal elsewhere, but thought I would try to give it separate title so people could find it later.
I felt like I needed the "Mike experience" after reading learning cocoa from Apple, so I could have before again reading learning cocoa from Apple in the future. Playing and getting confused before reading instructions helps read instructions, reading instructions and getting confused before playing helps playing.
That's what I will try to write about, though it is going to probably remain a head scratcher about learning this sort of stuff.
That you analyzed why the ball sometimes dissappeared was fantastic. Maybe we can all start to think and diagnose multithreaded as well as you!
I shall study your code candidates. -
Some changes and questions
2002-01-09 11:34:51 Michael Beam |
[Reply | View]
Wow, that's a lot to read! I hope i address all of you points, and if not, ask again :)
First: You are correct about the modification of the code that you proposed. This is indeed something you would want to do if you were programming a game or something that checks collisions. I was kind of hoping no one would change the speed near the edges :)
Second: Again, you are correct that you can import AnimationView.h into AnimationController.h to get rid of annoying build warnings. I should have mentioned that.
Third: Whoops! Typo! Thanks for catching that for me. I would never have seen that in a million years!
Fourth: [NSThread exit] is used when you want to stop a thread before the completion of the threaded method. In our application we have the neverending while loop, which means that the end of the animate: method will never be reached. This also means that the thread won't stop until the application quits. However, if the while loop did stop somehow and allow the remainder of animate: to finish executing, the thread would exit normally at the end, so we don't need to do [NSThread exit]. Originally i was going to put this line in at the end of animate:, but then i realized it was unnecessary, so i took it out. I thought i had cut out the accompanying explanation, but i guess i missed part of it.
From the NSThread reference:
"If you need to terminate the current thread before reaching the end of the initial selector, send the exit message to the NSThread class object."
Fifth: You're correct on this too, we really should have a dealloc method to make things proper. I've been kind of lazy about this, and will make a point in the future to include it.
Well, i hope i covered everything. That's all for now!
Mike
-
Using scrolling in NSView
2002-01-05 03:35:48 zeus [Reply | View]
Hi everyone,
I'm sorry to repost this topic here, but I hope it will give it more visibility, and since we are still speaking about graphics it isn't absolutely in the wrong place.
I try to generate a user interface for
a simple 2D grapher and in this soft I need to scroll my view. In fact I
have a subclass of NSView in wich i'm drawing my function (i.e y=x^2) and I
want to be able to click on one point of my NSView and get the new view
centered where I clicked. In order to get that I override the methode
mouseDown.
Here's the code:
-(void)mouseDown:(NSEvent *) theEvent{
NSPoint loc = [theEvent locationInWindow];
loc.x -= [self frame].origin.x;
loc.y -= [self frame].origin.y;
[self scrollPoint:loc];
[self setNeedsDisplay:YES];
}
That is working: I explain no error during compilation, no error when
running but nothing happened when I click. And the only thing i'm sure is
that i'm going into thi method because when I set a breakpoint to see if
there's a NSPoint loc create, I'm able to see it and the coordinates i get
seems to be ok.
Thanks to anyone who can help me.
Regards Jerome
-
Using scrolling in NSView
2002-01-06 13:03:33 michele [Reply | View]
Hi Jerome,
I'm not sure you have to use scrolling to do what you need.
Read Using Transforms in Basic Drawing in Cocoa Programming Topics.
For what I've understood, transforms are used most commonly to adjust the view around a defined point (that's exactly what scrolling does).
Well, I'm very very new to Cocoa, but anyway you can give it a try.
Michèle -
Using scrolling in NSView
2002-01-09 12:40:59 zeus [Reply | View]
Read Using Transforms in Basic Drawing in Cocoa Programming Topics.
Sorry but I can't hardly find that page could you give me the direct link to that page.
@+ Jerome -
Using scrolling in NSView
2002-01-10 13:42:51 michele [Reply | View]
Hello Jerome,
You can access this page directly in Project Builder, using the help menu.
Choose Cocoa Help, then circa the middle of the page you have Programming Topics. Within this paragraph, you'll see Drawing and Imaging. Choose the second topic: Basic Drawing.
When the new page appears on the screen, choose the third topic on the left side: coordinate transforms. The third paragraph is Using tranforms.
Hope this helps you.
Michèle -
Using scrolling in NSView
2002-01-11 08:44:34 zeus [Reply | View]
Thanks Michèle,
I was 2k km away from thinking that it was on the Documentation of Cocoa. I saught that on the Tutorial from Mike (don't even ask me why...)
Second point: Even after this explanation I were still unable to find that doc. (Explanation my doc is coming from the realase of Semptember 2k+1).
Third point: I Finally found it online. If there is anyone interested take a look at:
http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/DrawBasic/index.html
Hope this will help me.
@+ Jerome






NSArray *myArray; //interface declaration
NSBezierPath *path; //interface decl.
//in implementation
path = [[NSBezierPath bezierPath] retain];
myArray = [NSArray arrayWithObjects:path count:10];
When I run the program, I get the following output in the console:
2004-01-03 20:38:30.510 Galaxies[5578] An uncaught exception was raised
2004-01-03 20:38:30.510 Galaxies[5578] *** -[NSPlaceholderArray initWithObjects:count:]: attempt to insert nil
2004-01-03 20:38:30.510 Galaxies[5578] *** Uncaught exception: <NSInvalidArgumentException> *** -[NSPlaceholderArray initWithObjects:count:]: attempt to insert nil
Galaxies has exited due to signal 5 (SIGTRAP).
I'm trying to draw galaxies, with each star being an NSBezierPath object, so that's why I'm trying to do it with arrays. I wouldn't want to have to make each star individually, since there are hundreds of them.