I have a main thread which is my Cocoa Application. I want the user interface to remain responsive and am detatching another thread (when the user clicks a button) that will perform many computations. What I want is that when this secondary thread exits I want a notification. I read that performSelectorOnMainThread withObject waitUntilDone: was a “light weight” way to achive this.
What I have noticed is that:
My question is whether there is a way to use an instance method because I would like the graphics to be updated once the computations are complete (but I cannot use General/OpenGL in the detached thread). I will note the code segment I think are really germane by using the codesegment text.
As is the compiler compains that instance variablesis “accessed in a class method”. Since I am trying to send messages to an N
The program draws fractals. So I want the computing to be performed independently of the GUI. ** «common.h» **
/*
#import <Cocoa/Cocoa.h>
#define SIZE_X (600) #define SIZE_Y (600)
typedef struct { UInt32 x; UInt32 y; } coord ;
typedef struct { float real; float imag; } imaginary;
typedef struct { imaginary initialPhysicalLocation; float step; unsigned int escape; unsigned int numColors; // unsigned int **colorIndex; coord pixels; clock_t timeStart; clock_t timeStop; unsigned int pixelMap[SIZE_X][SIZE_Y];
} fracInit, *pfracInit;
** «iFract.h» **
/* iFract */
#import <Cocoa/Cocoa.h>
#define TAG_X (0) #define TAG_Y (1) #define TAG_STEP (2) #define TAG_ESCAPE (3) #define TAG_COLORS (4)
@interface iFract : General/NSObject { General/IBOutlet id General/TopRightLoc; General/IBOutlet id General/BottomLeftLoc; General/IBOutlet id Status; General/IBOutlet id General/DrawButton; General/IBOutlet id General/TimeToCompute; General/IBOutlet id drawPort; General/IBOutlet id location; General/IBOutlet id progress;
General/NSMutableData *initData;
}
#define DRAW #define THREADS
**
#ifdef THREADS
(void) performFractalDrawing: (id)anObject; #endif </code> **
@end
** «iFract.m» **
#import “iFract.h” #import <General/OpenGL/gl.h> #import <vecLib/vectorOps.h>
#import “common.h”
float complexMagnitudeSquared(imaginary *val); unsigned int iterate(imaginary *initVal, imaginary *constant, float escapeMagSquared, unsigned int escapeIterations);
@implementation iFract
/####################################/ -(void)dealloc /####################################/ { [super dealloc]; }
/####################################/
initialLocation.real = -0.74; initialLocation.imag = 0; step = 0.005;
[Status setStringValue: @”Ready”]; General/[TimeToCompute setStringValue: @”–”]; General/location cellAtIndex: [location indexOfCellWithTag: TAG_X setFloatValue: initialLocation.real]; General/location cellAtIndex: [location indexOfCellWithTag: TAG_Y setFloatValue: initialLocation.imag]; General/location cellAtIndex: [location indexOfCellWithTag: TAG_STEP setFloatValue: step]; General/location cellAtIndex: [location indexOfCellWithTag: TAG_ESCAPE setFloatValue: 8.0]; General/location cellAtIndex: [location indexOfCellWithTag: TAG_COLORS setIntValue: 64];
[self updateLocation]; }
**
/******************************************/
+(void)postDrawCleanup: (id)anObject;
/******************************************/
{
#if 1
pfracInit init;
init = (fracInit *)[initData mutableBytes];
General/[DrawButton setEnabled: TRUE]; [Status setStringValue: @”Done”];
General/[TimeToCompute setFloatValue: ((float)init->timeStop - init->timeStart )/CLOCKS_PER_SEC ]; [self draw]; [initData release]; #endif
} </code> **
/**************/ -(void)draw /**************/ { //imaginary initialVal, screenPos, screenStep, physicalPos, physicalStep, initialPhysicalPos; //unsigned int iterations, escape, numColors; imaginary screenPos, screenStep; unsigned int iterations, numColors; coord index; pfracInit init;
init = (fracInit *)[initData mutableBytes];
index.x = index.y = 0; screenPos.real = screenPos.imag = -1; screenStep.real = screenStep.imag = init->step; numColors = init->numColors;
#ifdef DRAW glClearColor( 0, 0, 0, 0 ) ; glPointSize(1.0); glClear( GL_COLOR_BUFFER_BIT ) ; #endif
for(index.y = 0; index.y < SIZE_Y; index.y++ ) {
screenPos.real = -1;
for(index.x = 0; index.x < SIZE_X; index.x++ ) {
// draw the point at the present location #ifdef DRAW
glBegin( GL_POINTS ) ;
{
glColor3f( 0.0f, ((float)iterations /numColors), 0.0f ) ;
glVertex2f(screenPos.real, screenPos.imag ) ;
}
glEnd() ; #endif
screenPos.real += screenStep.real;
}
screenPos.imag += screenStep.imag;
} #ifdef DRAW glFlush() ; #endif
}
/**************/
initialLocation.real = General/location cellAtIndex: [location indexOfCellWithTag: TAG_X floatValue]; initialLocation.imag = General/location cellAtIndex: [location indexOfCellWithTag: TAG_Y floatValue]; step = General/location cellAtIndex: [location indexOfCellWithTag: TAG_STEP floatValue];
initialLocation.real += stepSIZE_X/2 ; // top right coordinates initialLocation.imag += stepSIZE_Y/2 ; // top right coordinates
General/[TopRightLoc setStringValue: General/[NSString stringWithFormat: @”(%f, %f)”, initialLocation.real, initialLocation.imag] ];
initialLocation.real -= stepSIZE_X ; // top right coordinates initialLocation.imag -= stepSIZE_Y ; // top right coordinates
General/[BottomLeftLoc setStringValue: General/[NSString stringWithFormat: @”(%f, %f)”, initialLocation.real, initialLocation.imag] ]; }
/**************/
//General/[DrawButton setEnabled: FALSE]; [Status setStringValue: @”Processing…”]; General/[TimeToCompute setStringValue: @”–”];
// Set up structure initParams.step = General/location cellAtIndex: [location indexOfCellWithTag: TAG_STEP floatValue]; initParams.initialPhysicalLocation.real = General/location cellAtIndex: [location indexOfCellWithTag: TAG_X floatValue] - initParams.stepSIZE_X/2; initParams.initialPhysicalLocation.imag = General/location cellAtIndex: [location indexOfCellWithTag: TAG_Y floatValue] - initParams.stepSIZE_Y/2; initParams.escape = General/location cellAtIndex: [location indexOfCellWithTag: TAG_ESCAPE floatValue]; initParams.numColors = General/location cellAtIndex: [location indexOfCellWithTag: TAG_COLORS intValue]; initParams.pixels.x = SIZE_X; initParams.pixels.y = SIZE_Y;
initParams.timeStart = clock();
[self updateLocation];
initData = General/[NSMutableData dataWithData: General/[NSData dataWithBytes: &initParams length: sizeof(fracInit)]]; [initData retain];
**
#ifdef THREADS
// wait for imaging of fractial to complete
General/[NSThread detachNewThreadSelector: @selector(performFractalDrawing:) toTarget:[self class] withObject: initData];
#else
[self performFractalDrawing: initData];
[self postDrawCleanup];
#endif
**
}
** /********************’/ #ifdef THREADS
pfracInit init; General/NSAutoreleasePool *pool = General/[[NSAutoreleasePool alloc] init];
General/NSLog(@”In the thread”); init = (fracInit *)[anObject mutableBytes];
// Get initial parameters from structure physicalStep.real = physicalStep.imag = init->step;
initialPhysicalPos.real = physicalPos.real = init->initialPhysicalLocation.real; initialPhysicalPos.imag = physicalPos.imag = init->initialPhysicalLocation.imag; escape = init->escape; numColors = init->numColors;
index.x = index.y = 0;
for(index.y = 0; index.y < SIZE_Y; index.y++ ) {
physicalPos.real = initialPhysicalPos.real;
for(index.x = 0; index.x < SIZE_X; index.x++ ) {
init->pixelMap[index.x][index.y] = iterate(&physicalPos, &physicalPos, escape, numColors);
physicalPos.real += physicalStep.real;
}
physicalPos.imag += physicalStep.imag;
}
init->timeStop = clock();
**
[self performSelectorOnMainThread: @selector(postDrawCleanup:) withObject: nil waitUntilDone: FALSE];
**
General/NSLog(@”Exiting the thread”);
[pool release]; }
@end
/****************’/ float complexMagnitudeSquared(imaginary val) /**************’/ { return(val->realval->real + val->imag*val->imag); }
/****************’/ unsigned int iterate(imaginary initVal, imaginary *constant, float escapeMagSquared, unsigned int escapeIterations) /***************’/ { unsigned int iterations; imaginary val; float tempReal;
iterations = escapeIterations;
val.real = initVal->real; val.imag = initVal->imag;
while(escapeIterations) { tempReal = val.real; val.real = val.realval.real - val.imagval.imag + constant->real; val.imag = 2tempRealval.imag + constant->imag ;
if(escapeMagSquared < complexMagnitudeSquared(&val) ) {
escapeIterations = iterations - escapeIterations;
break;
}
escapeIterations--;
}
return(escapeIterations); }
The reason why the detached thread is calling a class method is because you told it to:
General/[NSThread detachNewThreadSelector: @selector(performFractalDrawing:) toTarget:[self class] withObject: initData];
(you are targeting [self class] instead of self so you are targeting the class, not the instance)
Similarly with the performSelectorOnMainThread: call. You are sending it to self from within a class method so you are calling it on the class.
Does that help?
–General/JeffDisher
That does help. While the answer was simple and I do understand the distinction (now) I did not really understand how sending “[self class]” was causing the problem. I think the root of my problem was not understanding this.
–General/WayneContello
Okay, I will try to explain this.
Objective-C uses the OO concepts of General/SmallTalk (one of the purer OO languages - it is pretty sweet). In General/SmallTalk, everything is an object (even blocks of code are objects). Most importantly, is that classes are objects (they are instances of Metaclass, as I recall).
Classes have methods, just as instances have methods. self refers to the object which received the message you are currently in (unless you assign self, but that is a corner case which doesn’t usually apply outside of initializers). [self class] is the object which is the class which self is an instance of. Thus, messages sent to self will be received by the self instance. Methods sent to [self class] will be received by the class itself (hence why it wanted to see a class method). As to why the second method had to be a class method, self is going to refer to a class when inside a class method.
Does that explain it or is something still missing?
–General/JeffDisher