• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: NSThread question - DO to make it sing
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: NSThread question - DO to make it sing


  • Subject: Re: NSThread question - DO to make it sing
  • From: Candide Kemmler <email@hidden>
  • Date: Thu, 12 Jul 2001 11:20:31 +0200

Le jeudi 12 juillet 2001, ` 09:58, Dennis C. De Mars a icrit :

> on 7/11/01 10:39 AM, Candide Kemmler at email@hidden wrote:
>
>>
>> Le mercredi 11 juillet 2001, ` 06:57, Dennis C. De Mars a icrit :
>>
>>> on 7/11/01 8:47 AM, Candide Kemmler at email@hidden wrote:
>>>
>>>> Le mardi 10 juillet 2001, ` 06:54, Miguel Morales a icrit :
>>>>>
>>>>> However, this would spawn a thread, but the main thread would wait
>>>>> for
>>>>> the secondary thread to finish before continuing, and not give you
>>>>> any
>>>>> of the functionality you want of the main thread plugging along.
>>>>> This
>>>>> is where DO comes in. I will assume that there is a main object
>>>>> that
>>>>> is running in a run loop, and that when the button gets pushed the
>>>>> method -(void)button:(NSData *)data is called, and that there is
>>>>> another method in the object that draws to the screen (also in the
>>>>> main
>>>>> object) called -(oneway void)display:(bycopy NSData *)data.
>>>>
>>>> Great ! I've read the chapter on DO in "Object-Oriented Programming
>>>> and
>>>> the Objective-C Language" and I'm enthusiast about learning more on
>>>> DO
>>>> in OC. For a java-fan like me, it's like doing RMI and
>>>> multi-threading
>>>> at once ! However I find it a little odd to be forced to do rmi (or
>>>> rpc,
>>>> or whatever-you-name-it) just to do multi-threading.
>>>>
>>>> You said that the code snippet you give "would spawn a thread, but
>>>> the
>>>> main thread would wait for the secondary thread to finish before
>>>> continuing" !!!!! That's the whole point of doing threads !
>>>>
>>>> Consider the following bit of java code:
>>>>
>>>> public void actionPerformed ( ActionEvent evt ) {
>>>> if ( evt.getSource () == myButton ) {
>>>> ( new Thread () {
>>>> public void run () {
>>>> renderMyImage ();
>>>> }
>>>> } ).start ();
>>>> }
>>>> }
>>>>
>>>> Isn't there a way as simple as this do achieve the same effect in
>>>> Objective-C/Cocoa ?
>>>
>>> If your "renderMyImage" routine used any Swing classes to do its
>>> rendering,
>>> you'd have a problem with this code too, because Swing is not
>>> thread-safe
>>> either; you are supposed to do all drawing in the main thread there
>>> too.
>>>
>>> I think this is true of pretty much any GUI system of any complexity
>>> ever
>>> devised -- you simply have to defer drawing to the main thread.
>>>
>>> - Dennis D.
>>
>> consider the following renderMyImage implementation (not tested):
>>
>> java.awt.Image renderMyImage () {
>> java.awt.image.BufferedImage image = new
>> java.awt.image.BufferedImage ( 450, 345, BufferedImage.TYPE_INT_ARGB );
>> Graphics2D g2d = image.createGraphics ();
>> g2d.setColor ( Color.red );
>> g2d.fillRect ( 0, 0, 450, 345 );
>> return image;
>> }
>>
>> There's no Swing code involved, and now I have an image I can send to a
>> Swing component to draw it with something like
>>
>> g.drawImage ( image, 0, 0, this );
>>
>> Simple enough, huh ? And that's exactly what I'd like to do in
>> OC/Cocoa.
>
> Well, if you are talking about rendering an image offscreen in a
> secondary
> thread, but only displaying it onscreen in the main thread, I think you
> should be able to do that safely in Cocoa...if you look at:
>
> http://developer.apple.com/techpubs/macosx/ReleaseNotes/ThreadSupport.html
>
> ...they have a discussion of modifying NSViews in threads. Although I
> could
> have used a more thorough discussion than Apple provides in this release
> note, they seem to imply that the only thing to really avoid is doing
> actual
> on-screen updates anywhere but in the main thread, which is
> understandable
> since otherwise the main thread and another thread could be trying to
> modify
> the same on-screen pixels at the same time. But, if you have a thread
> drawing to an off-screen image that is owned by that thread, that should
> work. At least that's the impression I get, I haven't done too much of
> this
> myself.
>
> The original code you posted is doing its work offscreen, so I think it
> should be all right. Some of the errors you were getting might be due
> to the
> fact that the line:
>
> [ NSThread detachNewThreadSelector:@selector(renderImage)
> toTarget:mapRenderer withObject:data ];
>
> should have been
>
> [ NSThread detachNewThreadSelector:@selector(renderImage:)
> toTarget:mapRenderer withObject:data ];
>
> The colon is part of the selector name, so I think that's why you got
> several messages about an unrecognized selector.

Right, I didn't get that. It works now... most of it: it seems that the
image is rightly created and rendered, but nothing appears on-screen.
This is the whole chain of calls:

in MapController, when the button's triggered:

[ NSThread detachNewThreadSelector:@selector(renderImage:)
toTarget:mapRenderer withObject:data ];

in MapRenderer, this is the renderImage method:

- (oneway void) renderImage: (bycopy NSData *) data
{
id mainProxy;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSSize aSize;
NSImage *cachedImage;

NSLog ( @"in renderImage code" );
aSize = NSMakeSize ( 550, 445 );

cachedImage = [[NSImage alloc] initWithSize:aSize];

[cachedImage setBackgroundColor:[[NSColor redColor]];

[cachedImage lockFocus];
[[NSColor blackColor] set];
[NSBezierPath fillrect:NSMakeRect(0,0,aSize.width,aSize.height)];
[cachedImage unlockFocus];

[mainProxy setImage:cachedImage];

[pool release];
}

back in MapController, the Image is set (MapController is the
"mainThread" DO):

- (void) setImage:(NSImage *) anImage
{
NSLog ( @"setImage is invoked, its size is %f, %f", [anImage
size].width, [anImage size].height );
[mapView setImage:anImage ];
}

in MapView, setImage is defined like so:

- (void) setImage:(NSImage *) anImage
{
NSLog (@"set cachedImage in MapView" );
cachedImage = image;
NSLog ( @"setImage is invoked, its size is %f, %f", [cachedImage
size].width, [cachedImage size].height );
[self display];
}

Now, drawRect:

- (void) drawRect: (NSRect) frame
{
float cx = [self bounds].size.width/2;
float cy = [self bounds].size.height/2;
NSLog ( @"drawRect is invoked, cachedImage's size is %f, %f",
[cachedImage size].width, [cachedImage size].height );
cx -= [cachedImage size].width/2;
cy -= [cachedImage size].height/2;
[cachedImage compositeToPoint:NSMakePoint(cx,cy)
operation:NSCompositeSourceOver];
}

The size of the image is rightly logged every time, yet nothing appears
on-screen (neither a black nor a red rectangle). Everything seems
all-right to me though. Any Idea ? Oh, And my app just crashes with a
signal 10 (SIGBUS) when I try to resize its window...

Thanks for your help.

Candide

> - Dennis D.
> _______________________________________________
> cocoa-dev mailing list
> email@hidden
> http://www.lists.apple.com/mailman/listinfo/cocoa-dev


  • Follow-Ups:
    • Re: NSThread question - DO to make it sing
      • From: "David P. Henderson" <email@hidden>
References: 
 >Re: NSThread question - DO to make it sing (From: "Dennis C. De Mars" <email@hidden>)

  • Prev by Date: NSThread question - DO to make it sing
  • Next by Date: Re: Singleton instances and multithreading
  • Previous by thread: Re: NSThread question - DO to make it sing
  • Next by thread: Re: NSThread question - DO to make it sing
  • Index(es):
    • Date
    • Thread