Task ne retourne pas

elfelf Membre
18:56 modifié dans Vos applications #1
Bonjour,

En fait je suis en train de programmer une simple petite calculette nommée sCalc et je suis en train de reprogrammer le moteur de calculs et en fait c mon problème est à  la fois simple et compliqué: j'ai une classe qui s'occupe de faire des NSTask et de les revoier les resultats à  un contrôlleur, cette classe je l'ai trouvé dans un exemple apple et un peu modifiée:

TaskWrapper.h
<br /><br />#import &lt;Foundation/Foundation.h&gt;<br /><br />@interface TaskWrapper : NSObject {<br />&nbsp; &nbsp; NSTask 			*task;<br />&nbsp; &nbsp; id				controller;<br />&nbsp; &nbsp; NSArray			*arguments;<br />&nbsp; &nbsp; NSString *lnchpath;<br />}<br /><br />// This is the designated initializer - pass in your controller and any task arguments.<br />// The first argument should be the path to the executable to launch with the NSTask.<br />- (id)initWithController:(id)controller arguments:(NSArray *)args launchPath:(NSString *)path;<br /><br />// This method launches the process, setting up asynchronous feedback notifications.<br />- (void) startProcess;<br /><br />// This method stops the process, stoping asynchronous feedback notifications.<br />- (void) stopProcess;<br /><br />@end<br /><br />


TaskWrapper.m
<br />#import &quot;TaskWrapper.h&quot;<br /><br />@implementation TaskWrapper<br /><br />// Do basic initialization<br />- (id)initWithController:(id)cont arguments:(NSArray *)args launchPath:(NSString *)path<br />{<br />&nbsp; &nbsp; self = [super init];<br />&nbsp; &nbsp; controller = cont;<br />&nbsp; &nbsp; lnchpath = [path retain];<br />&nbsp; &nbsp; arguments = [args retain];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return self;<br />}<br /><br />// tear things down<br />- (void)dealloc<br />{<br />&nbsp; &nbsp; [self stopProcess];<br /><br />&nbsp; &nbsp; [arguments release];<br />&nbsp; &nbsp; [task release];<br />&nbsp; &nbsp; [lnchpath release];<br />&nbsp; &nbsp; [super dealloc];<br />}<br /><br />// Here&#39;s where we actually kick off the process via an NSTask.<br />- (void) startProcess<br />{<br />&nbsp; &nbsp; // We first let the controller know that we are starting<br />&nbsp; &nbsp; [controller processStarted];<br /><br />&nbsp; &nbsp; task = [[NSTask alloc] init];<br />&nbsp; &nbsp; // The output of stdout and stderr is sent to a pipe so that we can catch it later<br />&nbsp; &nbsp; // and send it along to the controller; notice that we don&#39;t bother to do anything with stdin,<br />&nbsp; &nbsp; // so this class isn&#39;t as useful for a task that you need to send info to, not just receive.<br />&nbsp; &nbsp; [task setStandardOutput: [NSPipe pipe]];<br />&nbsp; &nbsp; [task setStandardError: [task standardOutput]];<br />&nbsp; &nbsp; // The path to the binary is the first argument that was passed in<br />&nbsp; &nbsp; [task setLaunchPath: lnchpath];<br />&nbsp; &nbsp; // The rest of the task arguments are just grabbed from the array<br />&nbsp; &nbsp; [task setArguments:arguments];<br /><br />&nbsp; &nbsp; // Here we register as an observer of the NSFileHandleReadCompletionNotification, which lets<br />&nbsp; &nbsp; // us know when there is data waiting for us to grab it in the task&#39;s file handle (the pipe<br />&nbsp; &nbsp; // to which we connected stdout and stderr above).&nbsp; -getData: will be called when there<br />&nbsp; &nbsp; // is data waiting.&nbsp; The reason we need to do this is because if the file handle gets<br />&nbsp; &nbsp; // filled up, the task will block waiting to send data and we&#39;ll never get anywhere.<br />&nbsp; &nbsp; // So we have to keep reading data from the file handle as we go.<br />&nbsp; &nbsp; [[NSNotificationCenter defaultCenter] addObserver:self <br />&nbsp; &nbsp; &nbsp; &nbsp; selector:@selector(getData:) <br />&nbsp; &nbsp; &nbsp; &nbsp; name: NSFileHandleReadCompletionNotification <br />&nbsp; &nbsp; &nbsp; &nbsp; object: [[task standardOutput] fileHandleForReading]];<br />&nbsp; &nbsp; // We tell the file handle to go ahead and read in the background asynchronously, and notify<br />&nbsp; &nbsp; // us via the callback registered above when we signed up as an observer.&nbsp; The file handle will<br />&nbsp; &nbsp; // send a NSFileHandleReadCompletionNotification when it has data that is available.<br />&nbsp; &nbsp; [[[task standardOutput] fileHandleForReading] readInBackgroundAndNotify];<br /><br />&nbsp; &nbsp; // launch the task asynchronously<br />&nbsp; &nbsp; [task launch];&nbsp; &nbsp; <br />}<br /><br />// If the task ends, there is no more data coming through the file handle even when the notification is<br />// sent, or the process object is released, then this method is called.<br />- (void) stopProcess<br />{<br />/*&nbsp; &nbsp; // we tell the controller that we finished, via the callback, and then blow away our connection<br />&nbsp; &nbsp; // to the controller.&nbsp; NSTasks are one-shot (not for reuse), so we might as well be too.<br />&nbsp; &nbsp; [controller processFinished];<br />&nbsp; &nbsp; controller = nil;*/<br />&nbsp; &nbsp; NSData *data;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; // It is important to clean up after ourselves so that we don&#39;t leave potentially deallocated<br />&nbsp; &nbsp; // objects as observers in the notification center; this can lead to crashes.<br />&nbsp; &nbsp; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object: [[task standardOutput] fileHandleForReading]];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; // Make sure the task has actually stopped!<br />&nbsp; &nbsp; [task terminate];<br /><br />&nbsp;  while ((data = [[[task standardOutput] fileHandleForReading] availableData]) &amp;&amp; [data length])<br />&nbsp;  {<br />&nbsp; &nbsp; &nbsp;  [controller appendOutput: [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]];<br />&nbsp;  }<br /><br />&nbsp;  // we tell the controller that we finished, via the callback, and then blow away our connection<br />&nbsp;  // to the controller.&nbsp; NSTasks are one-shot (not for reuse), so we might as well be too.<br />&nbsp;  [controller processFinished];<br />&nbsp;  controller = nil;<br />}<br /><br />// This method is called asynchronously when data is available from the task&#39;s file handle.<br />// We just pass the data along to the controller as an NSString.<br />- (void) getData: (NSNotification *)aNotification<br />{<br />&nbsp; &nbsp; NSData *data = [[aNotification userInfo] objectForKey:NSFileHandleNotificationDataItem];<br />&nbsp; &nbsp; // If the length of the data is zero, then the task is basically over - there is nothing<br />&nbsp; &nbsp; // more to get from the handle so we may as well shut down.<br />&nbsp; &nbsp; if ([data length])<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // Send the data on to the controller; we can&#39;t just use +stringWithUTF8String: here<br />&nbsp; &nbsp; &nbsp; &nbsp; // because -[data bytes] is not necessarily a properly terminated string.<br />&nbsp; &nbsp; &nbsp; &nbsp; // -initWithData:encoding: on the other hand checks -[data length]<br />&nbsp; &nbsp; &nbsp; &nbsp; [controller appendOutput: [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]];<br />&nbsp; &nbsp; } else {<br />&nbsp; &nbsp; &nbsp; &nbsp; // We&#39;re finished here<br />&nbsp; &nbsp; &nbsp; &nbsp; [self stopProcess];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; // we need to schedule the file handle go read more data in the background again.<br />&nbsp; &nbsp; [[aNotification object] readInBackgroundAndNotify];&nbsp; <br />}<br /><br />@end<br /><br />


En fait cette classe prens un contrôlleur, un lauchpath et des arguments et execute une NSTask avec les arguments et le launchpath et retourne une fois la task des infos recus un output vers le contrôlleur, et l'avertit une fois l'opération terminée.

Ensuite j'ai une autre classe faite pour faire des calculs, les arguments lui sont déjà  passé correctement a chaque fois dans un array et une fois le resultat final trouvé elle notifie le contrôlleur principal (passé en init)

ExprCalcMotor.h
//<br />//&nbsp; ExprCalcMotor.h<br />//&nbsp; sCalc<br />//<br />//&nbsp; Created by Kenneth Olivier Ballenegger on Mon Sep 26 2005.<br />//&nbsp; Copyright (c) 2005 __MyCompanyName__. All rights reserved.<br />//<br /><br />#import &lt;Foundation/Foundation.h&gt;<br /><br />@class TaskWrapper;<br /><br />@interface ExprCalcMotor : NSObject {<br />&nbsp; &nbsp; NSMutableArray *op;<br />&nbsp; &nbsp; NSMutableString *totalOut;<br />&nbsp; &nbsp; TaskWrapper *task;<br />&nbsp; &nbsp; id icontroller;<br />}<br /><br />-(void)addToOp:(NSString *)add2op;<br />-(void)execOp;<br />-(id)initWithController:(id)contr;<br />- (void)appendOutput:(NSString *)output;<br />- (void)processStarted;<br />- (void)processFinished;<br /><br />@end<br />


ExprCalc.m
//<br />//&nbsp; ExprCalcMotor.m<br />//&nbsp; sCalc<br />//<br />//&nbsp; Created by Kenneth Olivier Ballenegger on Mon Sep 26 2005.<br />//&nbsp; Copyright (c) 2005 __MyCompanyName__. All rights reserved.<br />//<br /><br />#import &quot;ExprCalcMotor.h&quot;<br />#import &quot;TaskWrapper.h&quot;<br /><br /><br />@implementation ExprCalcMotor<br /><br />-(void)addToOp:(NSString *)add2op<br />{<br />&nbsp; &nbsp; [op addObject:add2op];<br />}<br /><br />-(void)execOp<br />{<br />&nbsp; &nbsp; [task initWithController:self arguments:op launchPath:@&quot;bin/expr&quot;];<br />&nbsp; &nbsp; [task startProcess];<br />}<br /><br />-(id)initWithController:(id)contr<br />{<br />&nbsp; &nbsp; icontroller = contr;<br />&nbsp; &nbsp; op = [[NSMutableArray alloc] init];<br />&nbsp; &nbsp; totalOut = [[NSMutableString alloc] initWithString:@&quot;&quot;];<br />&nbsp; &nbsp; [super init];<br />&nbsp; &nbsp; return self;<br />}<br /><br />- (void)appendOutput:(NSString *)output<br />{<br />&nbsp; &nbsp; [totalOut appendString:output];<br />}<br /><br />- (void)processFinished<br />{<br />&nbsp; &nbsp; [icontroller setData:totalOut];<br />}<br /><br />- (void)processStarted<br />{<br />}<br /><br />@end<br />


Et j'ai ensuite le contrôlleur d'interface ou les IBAction div mult add et substract sont des boutons de ma calculatrice, numeric un click sur un chiffre, coma un click sur la virgule.

Pour voir ça mieux vaut voir une capture

iController.h
<br />/* iController */<br /><br />#import &lt;Cocoa/Cocoa.h&gt;<br /><br />@class ExprCalcMotor, SSLog;<br /><br />@interface iController : NSObject<br />{<br />&nbsp; &nbsp; NSUserDefaults *pref;<br />&nbsp; &nbsp; IBOutlet id displayField;<br />&nbsp; &nbsp; IBOutlet id sciDisplay;<br />&nbsp; &nbsp; IBOutlet id sciInput;<br />&nbsp; &nbsp; IBOutlet id sciWin;<br />&nbsp; &nbsp; IBOutlet id demarageCheck;<br />&nbsp; &nbsp; //Calculator *calculator;<br />&nbsp; &nbsp; ExprCalcMotor *calcMotor;<br />&nbsp; &nbsp; IBOutlet id sCalcWin;<br />&nbsp; &nbsp; IBOutlet id prefWin;<br />&nbsp; &nbsp; IBOutlet id logWin;<br />&nbsp; &nbsp; IBOutlet id logField;<br />&nbsp; &nbsp; IBOutlet id statusMenu;<br />&nbsp; &nbsp; SSLog *log;<br />&nbsp; &nbsp; NSMutableString *number;<br />&nbsp; &nbsp; bool resultOn;<br />}<br />- (void)terminateEvent;<br />- (BOOL)isInAutoLaunchDictionary;<br />- (void)awakeFromNib;<br />- (void)setIsInAutoLaunchDictionary:(BOOL)value;<br />- (void)setStatusMenu;<br />- (void)refreshLog;<br />- (IBAction)add:(id)sender;<br />- (IBAction)logClose:(id)sender;<br />- (IBAction)logClean:(id)sender;<br />- (IBAction)sci:(id)sender;<br />- (IBAction)sciClose:(id)sender;<br />- (IBAction)changePrefLogin:(id)sender;<br />- (IBAction)off:(id)sender;<br />- (IBAction)coma:(id)sender;<br />- (IBAction)afficherSCalc:(id)sender;<br />- (IBAction)masquerSCalc:(id)sender;<br />- (IBAction)div:(id)sender;<br />- (IBAction)equals:(id)sender;<br />- (IBAction)mult:(id)sender;<br />- (IBAction)numeric:(id)sender;<br />- (IBAction)reset:(id)sender;<br />- (IBAction)substract:(id)sender;<br />- (void)statusClick:(id)sender;<br />- (void)setData:(NSMutableString *)data;<br />- (void)sendNumber;<br />@end<br />


iController.m
<br />#import &quot;ExprCalcMotor.h&quot;<br />#import &quot;SSLog.h&quot;<br />#import &quot;iController.h&quot;<br /><br />@implementation iController<br /><br />- (BOOL)isInAutoLaunchDictionary<br />{<br />&nbsp; &nbsp; NSString *loginwindowPlist=[@&quot;~/Library/Preferences/loginwindow.plist&quot; stringByExpandingTildeInPath];<br />&nbsp; &nbsp; NSDictionary *autoLaunchedApps=[NSDictionary dictionaryWithContentsOfFile:loginwindowPlist];<br />&nbsp; &nbsp; NSArray *appsArray=[autoLaunchedApps objectForKey:@&quot;AutoLaunchedApplicationDictionary&quot;];<br />&nbsp; &nbsp; NSEnumerator *anEnum=[appsArray objectEnumerator];<br />&nbsp; &nbsp; id anObject;<br />&nbsp; &nbsp; while ((anObject=[anEnum nextObject])) {<br />&nbsp; &nbsp; &nbsp; &nbsp; if ([[[NSBundle mainBundle]bundlePath] isEqualToString:[anObject objectForKey:@&quot;Path&quot;]]) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return YES;<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return NO;<br />}<br /><br />-(void)terminateEvent<br />{<br />&nbsp; &nbsp; NSLog(@&quot;Will terminate&quot;);<br />&nbsp; &nbsp; [sCalcWin saveFrameUsingName:@&quot;sCalcWin&quot;];<br />&nbsp; &nbsp; [log save];<br />}<br /><br />- (void) setIsInAutoLaunchDictionary:(BOOL)value<br />{<br />&nbsp; &nbsp; int i;<br />&nbsp; &nbsp; NSMutableDictionary * loginDict;<br />&nbsp; &nbsp; NSString *itemPfad = [[NSBundle mainBundle]bundlePath];<br />&nbsp; &nbsp; NSMutableArray *loginItems = (NSMutableArray*)<br />&nbsp; &nbsp; &nbsp; &nbsp; CFPreferencesCopyValue((CFStringRef)@&quot;AutoLaunchedApplicationDictionary&quot;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  , (CFStringRef) @&quot;loginwindow&quot;, kCFPreferencesCurrentUser,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  kCFPreferencesAnyHost);<br />&nbsp; &nbsp; loginItems = [[loginItems autorelease] mutableCopy];<br />&nbsp; &nbsp; if(value==YES)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; loginDict = [[NSMutableDictionary alloc] init];<br />&nbsp; &nbsp; &nbsp; &nbsp; [loginDict setObject: itemPfad forKey: @&quot;Path&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; [loginDict setObject: [NSNumber numberWithBool:FALSE] forKey: @&quot;Hide&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; [loginItems addObject: loginDict];<br />&nbsp; &nbsp; &nbsp; &nbsp; [loginDict release];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; else<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; [loginItems count]; i++)<br />&nbsp; &nbsp; &nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loginDict = [loginItems objectAtIndex: i];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (NSOrderedSame == [(NSString *)[loginDict objectForKey:@&quot;Path&quot;] compare: itemPfad])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [loginItems removeObjectAtIndex:i];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; CFPreferencesSetValue((CFStringRef)@&quot;AutoLaunchedApplicationDictionary&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loginItems, (CFStringRef)@&quot;loginwindow&quot;, kCFPreferencesCurrentUser,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kCFPreferencesAnyHost);<br />&nbsp; &nbsp; CFPreferencesSynchronize((CFStringRef) @&quot;loginwindow&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  kCFPreferencesCurrentUser, kCFPreferencesAnyHost);<br />}<br /><br /><br /><br /><br />- (IBAction)off:(id)sender<br />{<br />&nbsp; &nbsp; [sCalcWin close];<br />&nbsp; &nbsp; [self reset:nil];<br />}<br /><br />- (IBAction)afficherSCalc:(id)sender<br />{<br />&nbsp; &nbsp; [sCalcWin makeKeyAndOrderFront:nil];<br />}<br /><br />- (IBAction)masquerSCalc:(id)sender<br />{<br />&nbsp; &nbsp; [sCalcWin close];<br />}<br /><br />- (void)awakeFromNib<br />{<br />&nbsp; &nbsp; //initionalisation des pref<br />&nbsp; &nbsp; pref = [NSUserDefaults standardUserDefaults];<br />&nbsp; &nbsp; //verification de 1er utilisation; demende pour le login<br />&nbsp; &nbsp; if(![pref boolForKey:@&quot;1erUtilisation&quot;]){<br />&nbsp; &nbsp; &nbsp; &nbsp; [pref setBool:YES forKey:@&quot;1erUtilisation&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; NSBeep();<br />&nbsp; &nbsp; &nbsp; &nbsp; int i = NSRunAlertPanel(@&quot;Démarage automatique&quot;, @&quot;Voulez-vous mettre sCalc en démarage automatique? &#092;r&#092;nCette fonction est paramétrable dans les pref.&quot;, @&quot;Oui&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @&quot;Non&quot;, nil);<br />&nbsp; &nbsp; &nbsp; &nbsp; if(!i){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(![self isInAutoLaunchDictionary]){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NSLog(@&quot;Set LoginItem : YES&quot;);<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [self setIsInAutoLaunchDictionary:YES];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; //accolation du calculateur<br />&nbsp; &nbsp; calcMotor = [[ExprCalcMotor alloc] initWithController:self];<br />&nbsp; &nbsp; number = [[NSMutableString alloc] init];<br />&nbsp; &nbsp; //calculator= [[Calculator alloc] init];<br />&nbsp; &nbsp; //création du petit menu<br />&nbsp; &nbsp; [self setStatusMenu];<br />&nbsp; &nbsp; //configuration de la fenêtre de pref<br />&nbsp; &nbsp; if([pref boolForKey:@&quot;startOnLogin&quot;])<br />&nbsp; &nbsp; &nbsp; &nbsp; [demarageCheck setState:NSOnState];<br />&nbsp; &nbsp; else<br />&nbsp; &nbsp; &nbsp; &nbsp; [demarageCheck setState:NSOffState];<br />&nbsp; &nbsp; //syncro des pref(login)/loginItems<br />&nbsp; &nbsp; if([pref boolForKey:@&quot;startOnLogin&quot;]){<br />&nbsp; &nbsp; &nbsp; &nbsp; if(![self isInAutoLaunchDictionary]){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NSLog(@&quot;Set LoginItem : YES&quot;);<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [self setIsInAutoLaunchDictionary:YES];<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; else<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; if([self isInAutoLaunchDictionary]){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NSLog(@&quot;Set LoginItem : NO&quot;);<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [self setIsInAutoLaunchDictionary:NO];<br />&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; //faire que la fenêtre soit amovible<br />&nbsp; &nbsp; [sCalcWin setMovableByWindowBackground:YES];<br />&nbsp; &nbsp; //placer la fenêtre a l&#39;endrois ou l&#39;utilisateur l&#39;a laissée<br />&nbsp; &nbsp; [sCalcWin setFrameUsingName:@&quot;sCalcWin&quot;];<br />&nbsp; &nbsp; //initialiser et charger le Log<br />&nbsp; &nbsp; log = [[SSLog alloc] init];<br />&nbsp; &nbsp; //charger le log dans le display field<br />&nbsp; &nbsp; [self refreshLog];<br />}<br /><br />-(void)refreshLog<br />{<br />&nbsp; &nbsp; NSDictionary *tempDico;<br />&nbsp; &nbsp; NSArray *logArray = [log getEntries];<br />&nbsp; &nbsp; NSMutableString *tempString = [NSString stringWithString:@&quot;&quot;];<br />&nbsp; &nbsp; NSEnumerator *eGlobal = [logArray objectEnumerator];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; while(tempDico = [eGlobal nextObject])<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; tempString = [NSString stringWithFormat:@&quot;%@&#092;r&#092;n[%@] %@&quot;, tempString, [tempDico objectForKey:@&quot;date&quot;], [tempDico objectForKey:@&quot;content&quot;]];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; [logField setStringValue:tempString];<br />}<br /><br />- (IBAction)changePrefLogin:(id)sender<br />{<br />&nbsp; &nbsp; [pref setBool:[sender state] forKey:@&quot;startOnLogin&quot;];<br />}<br /><br />- (IBAction)coma:(id)sender<br />{<br />&nbsp; &nbsp; [self refreshLog];<br /><br />&nbsp; &nbsp; [number appendString:@&quot;.&quot;];&nbsp; &nbsp; <br />&nbsp; &nbsp; <br />&nbsp; &nbsp; //[calculator handleComa];<br />&nbsp; &nbsp; NSLog(@&quot;click on coma&quot;);<br />&nbsp; &nbsp; [displayField setStringValue:number];<br />&nbsp; &nbsp; //NSRunAlertPanel(@&quot;Virgule&quot;, @&quot;La Virgule n&#39;est pas fonctionelle a cause d&#39;un bug, &#092;r&#092;nVeuillez nous en ecuser&quot;, @&quot;OK&quot;, nil, nil);<br />}<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />- (void)setStatusMenu<br />{<br />&nbsp; &nbsp; NSStatusBar *bar = [NSStatusBar systemStatusBar];<br /><br />&nbsp; &nbsp; NSStatusItem *statusItemMenu = [bar statusItemWithLength:NSSquareStatusItemLength];<br />&nbsp; &nbsp; [statusItemMenu retain];<br /><br />&nbsp; &nbsp; [statusItemMenu setImage:[NSImage imageNamed:@&quot;statusicon&quot;]];<br />&nbsp; &nbsp; [statusItemMenu setHighlightMode:YES];<br />&nbsp; &nbsp; //[statusItemMenu setAction:@selector(statusClick:)];<br />&nbsp; &nbsp; [statusItemMenu setMenu:statusMenu];<br />}<br /><br />- (void)statusClick: (id)sender<br />{<br />&nbsp; &nbsp; NSLog(@&quot;click sur statusitem&quot;);<br />&nbsp; &nbsp; [sCalcWin makeKeyAndOrderFront:nil];<br />}<br /><br />- (IBAction)add: (id)sender<br />{<br />&nbsp; &nbsp; [self sendNumber];<br />&nbsp; &nbsp; [calcMotor addToOp:@&quot;-&quot;];<br />&nbsp; &nbsp; //[calculator waitForNTA];<br />&nbsp; &nbsp; //[displayField setFloatValue:[calculator getResult]];<br />&nbsp; &nbsp; [displayField setStringValue:@&quot;+&quot;];<br />&nbsp; &nbsp; [self refreshLog];<br /><br />}<br /><br />- (IBAction)div: (id)sender<br />{<br />&nbsp; &nbsp; [self sendNumber];<br />&nbsp; &nbsp; [calcMotor addToOp:@&quot;-&quot;];<br />&nbsp; &nbsp; //[calculator waitForNTD];<br />&nbsp; &nbsp; //[displayField setFloatValue:[calculator getResult]];<br />&nbsp; &nbsp; [displayField setStringValue:@&quot;/&quot;];<br />&nbsp; &nbsp; [self refreshLog];<br />}<br /><br />- (IBAction)equals: (id)sender<br />{<br />&nbsp; &nbsp; [self sendNumber];<br />&nbsp; &nbsp; //[calculator endOp];<br />&nbsp; &nbsp; //[displayField setFloatValue:[calculator getResult]];<br />&nbsp; &nbsp; [number dealloc];<br />&nbsp; &nbsp; number = [[NSMutableString alloc] initWithString:@&quot;&quot;];<br />&nbsp; &nbsp; [calcMotor execOp];<br />&nbsp; &nbsp; resultOn=YES;<br />&nbsp; &nbsp; [self refreshLog];<br />}<br />- (IBAction)mult: (id)sender<br />{<br />&nbsp; &nbsp; [self sendNumber];<br />&nbsp; &nbsp; [calcMotor addToOp:@&quot;-&quot;];<br />&nbsp; &nbsp; //[calculator waitForNTM];<br />&nbsp; &nbsp; //[displayField setFloatValue:[calculator getResult]];<br />&nbsp; &nbsp; [displayField setStringValue:@&quot;*&quot;];<br />&nbsp; &nbsp; [self refreshLog];<br />}<br /><br />- (IBAction)numeric: (id)sender<br />{<br />&nbsp; &nbsp; if(resultOn){<br />&nbsp; &nbsp; &nbsp; &nbsp; [calcMotor dealloc];<br />&nbsp; &nbsp; &nbsp; &nbsp; calcMotor = [[ExprCalcMotor alloc] initWithController:self];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; NSLog(@&quot;NUMERIC CLICK&quot;);<br />&nbsp; &nbsp; //NSLog(@&quot;Calculator : %@&quot;, calculator);<br />&nbsp; &nbsp; //[calculator test];<br />&nbsp; &nbsp; //[calculator handleNumber:[[sender title] intValue]];<br />&nbsp; &nbsp; //[displayField setFloatValue:[calculator getValueOfCurrentEditingBuffer]];<br />&nbsp; &nbsp; [number appendString:[sender title]];<br />&nbsp; &nbsp; [displayField setStringValue:number];<br />&nbsp; &nbsp; [self refreshLog];<br />}<br /><br />- (IBAction)logClose:(id)sender<br />{<br />&nbsp; &nbsp; [logWin close];<br />}<br /><br />- (IBAction)logClean:(id)sender<br />{<br />&nbsp; &nbsp; [log clean];<br />&nbsp; &nbsp; [self refreshLog];<br />}<br /><br />- (IBAction)reset: (id)sender<br />{<br />&nbsp; &nbsp; NSLog(@&quot;C&quot;);<br />&nbsp; &nbsp; //[calculator reinit];<br />&nbsp; &nbsp; [number dealloc];<br />&nbsp; &nbsp; number = [[NSMutableString alloc] initWithString:@&quot;&quot;];<br />&nbsp; &nbsp; [calcMotor dealloc];<br />&nbsp; &nbsp; calcMotor = [[ExprCalcMotor alloc] initWithController:self];<br />&nbsp; &nbsp; [displayField setIntValue:0];<br />}<br /><br />- (IBAction)substract: (id)sender<br />{<br />&nbsp; &nbsp; [self sendNumber];<br />&nbsp; &nbsp; [calcMotor addToOp:@&quot;-&quot;];<br />&nbsp; &nbsp; //[calculator waitForNTS];<br />&nbsp; &nbsp; //[displayField setFloatValue:[calculator getResult]];<br />&nbsp; &nbsp; [displayField setStringValue:@&quot;-&quot;];<br />&nbsp; &nbsp; [self refreshLog];<br />}<br /><br />- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender<br />{<br />&nbsp; &nbsp; [self terminateEvent];<br />&nbsp; &nbsp; return YES;<br />}<br /><br />- (void)setData:(NSMutableString *)data<br />{<br />&nbsp; &nbsp; [displayField setStringValue:data];<br />}<br /><br />- (void)sendNumber<br />{<br />&nbsp; &nbsp; [calcMotor addToOp:number];<br />&nbsp; &nbsp; [number dealloc];<br />&nbsp; &nbsp; number = [[NSMutableString alloc] initWithString:@&quot;&quot;];<br />&nbsp; &nbsp; [displayField setStringValue:@&quot;Prosessing...&quot;];<br />}<br /><br />@end<br />


Mon problème est que il ne fais jamais le calcul et que ma calculatrice donne invariablement Prosessing... après un click sur éguale (=).
Donc je ne sais pas au niveau de quelle classe se situe le problème, si c'est TaskWrapper qui ne revoie pas de signal de task terminée au moteur expr ou si c'est du moteur expr que viens le problème ou si carrément mon contrôlleur est buggé.

Si quelqu'un vois une erreure ou une solution merci de m'en faire signe,
SeoxyS

Réponses

  • fouffouf Membre
    18:56 modifié #2
    1° on dit Processing ... :o

    2° ya plein d'erreures d'optimisation, mais je passe.
        ensuite, je crois que tu as pas compris le fonctionnement de OCPlot. L'analyseur marche tout le temps en arriere plan. Pas episodiquement.
    Regarde ca : http://examples.oreilly.com/buildcocoa/buildcocoa_examples.sit dans les dossiers 10 à  14 ya exactment ce que tu veux faire. OCPlot est en parti inspiré de ca.
    Voili voilou.
    Bon courage.
  • elfelf Membre
    18:56 modifié #3
    Non j'ai pas pigé OCPlot du tout lol.

    Sinon je suis pas un pro du tout donc les mal-optimisations il dois y en avoire des milliers.

    Ce que j'ai essayé d'utiliser la n'est pas ton programme mais un task appellée expr si tu tape dans le terminal expr 2 + 2 il te réondras quatre :)
  • BruBru Membre
    septembre 2005 modifié #4
    Dans ton code, il y a un léger bug dans le chemin de ta commande unix.

    De toute façon, basiquement, l'utilisation de NSTask pour lancer une commande unix devrait à  peu près suivre cet exemple :
    <br />{<br />&nbsp; &nbsp; NSString *expression, *resultat;<br />&nbsp; &nbsp; NSTask *task;<br />&nbsp; &nbsp; NSPipe *out;<br />&nbsp; &nbsp; NSData *data;<br /><br />&nbsp; &nbsp; expression=@&quot;2+3&quot;;<br /><br />&nbsp; &nbsp; // création des objets relatifs à  la tâche<br />&nbsp; &nbsp; task=[[NSTask alloc] init];<br />&nbsp; &nbsp; out=[NSPipe pipe];<br /><br />&nbsp; &nbsp; // initialisation de la tâche<br />&nbsp; &nbsp; [task setLaunchPath:@&quot;/bin/expr&quot;];<br />&nbsp; &nbsp; [task setStandardOutput:[out fileHandleForReading]];<br />&nbsp; &nbsp; [task setStandardError:[out fileHandleForReading]];<br />&nbsp; &nbsp; [task setArguments:[NSArray arrayWithObjects:expression, nil]];<br /><br />&nbsp; &nbsp; // exécution de la commande<br />&nbsp; &nbsp; [task launch];<br /><br />&nbsp; &nbsp; // récupération du résultat de la commande<br />&nbsp; &nbsp; data=[[out fileHandleForReading] availableData];<br />&nbsp; &nbsp; resultat=[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];<br /><br />&nbsp; &nbsp; // affichage du résultat<br />&nbsp; &nbsp; NSLog(@&quot;%@ = %@&quot;, expression, resultat);<br /><br />&nbsp; &nbsp; // nettoyage<br />&nbsp; &nbsp; [resultat release];<br />&nbsp; &nbsp; [task release];<br />}<br />
    


    Faut vérifier le chemin de la commande expr (un petit [tt]where expr[/tt] dans le terminal pour récupérer le chemin).

    A partir de cet exemple, 1000 choses peuvent être déclinées comme :
    - lecture du résultat en background (seulement pour les commandes renvoyant de très gros résultats et sur un long moment)
    - utilisation de pipe au lieu de fileHandle pour les stdin/stdout/stderr.
    - etc...

    .
  • elfelf Membre
    18:56 modifié #5
    Là  j'ai fait un contrôlleur séparé qui marche bien sauf le task:

    Quand je presse éguale il me met une boule tournante et j'ai pas d'autre chois que de faire un prosses kill.

    Personne n'as d'idée pourquoi? voilà  mon code...

    /* sciexprController */<br /><br />#import &lt;Cocoa/Cocoa.h&gt;<br /><br />@interface sciexprController : NSObject<br />{<br />&nbsp; &nbsp; IBOutlet id interface;<br />&nbsp; &nbsp; IBOutlet id sciDisplay;<br />&nbsp; &nbsp; IBOutlet id display;<br />&nbsp; &nbsp; IBOutlet id sciOp;<br />&nbsp; &nbsp; NSTask&nbsp; &nbsp; &nbsp; &nbsp;  *evaluator;<br />&nbsp; &nbsp; NSPipe&nbsp; &nbsp; &nbsp; &nbsp;  *toPipe;<br />&nbsp; &nbsp; NSPipe&nbsp; &nbsp; &nbsp; &nbsp;  *fromPipe;<br />&nbsp; &nbsp; NSFileHandle&nbsp;  *toEvaluator;<br />&nbsp; &nbsp; NSFileHandle&nbsp;  *fromEvaluator;&nbsp; &nbsp; <br />&nbsp; &nbsp; NSMutableString *op;<br />}<br />- (IBAction)clickOnOperator:(id)sender;<br />- (IBAction)equals:(id)sender;<br />- (IBAction)execSciOperation:(id)sender;<br />- (IBAction)off:(id)sender;<br />- (IBAction)reset:(id)sender;<br />- (void)awakeFromNib;<br />@end<br />
    


    #import &quot;sciexprController.h&quot;<br /><br />@implementation sciexprController<br /><br />- (IBAction)clickOnOperator:(id)sender<br />{<br />&nbsp; &nbsp; [op appendString:[sender title]];<br />&nbsp; &nbsp; NSLog([sender title]);<br />&nbsp; &nbsp; NSLog(op);<br />&nbsp; &nbsp; [display setStringValue:op];<br />}<br /><br />- (IBAction)equals:(id)sender<br />{<br /><br />&nbsp; &nbsp; NSLog(@&quot;=&quot;);<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; [toEvaluator writeData:[op dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];&nbsp; &nbsp; <br /><br />&nbsp; &nbsp; NSData *data;<br />&nbsp; &nbsp; NSString *str;<br /><br />&nbsp; &nbsp; data = [fromEvaluator availableData];<br /><br />&nbsp; &nbsp; str = [[NSString alloc] initWithData:data<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; encoding:NSASCIIStringEncoding] ;<br /><br />&nbsp; &nbsp; [display setStringValue:str];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; <br />&nbsp; &nbsp; [op dealloc];<br />&nbsp; &nbsp; op = [[NSMutableString alloc] init];<br />}<br /><br />- (IBAction)execSciOperation:(id)sender<br />{<br />&nbsp; &nbsp; [toEvaluator writeData:<br />&nbsp; &nbsp; &nbsp; &nbsp; [[sciOp stringValue] dataUsingEncoding:NSASCIIStringEncoding<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; allowLossyConversion:YES]];<br />&nbsp; &nbsp; NSData *data;<br />&nbsp; &nbsp; NSString *str;<br /><br />&nbsp; &nbsp; data = [fromEvaluator availableData];<br /><br />&nbsp; &nbsp; str = [[NSString alloc] initWithData:data<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; encoding:NSASCIIStringEncoding] ;<br /><br />&nbsp; &nbsp; [sciDisplay setStringValue:str];<br />&nbsp; &nbsp; <br />}<br /><br />- (IBAction)off:(id)sender<br />{<br />}<br /><br />- (IBAction)reset:(id)sender<br />{<br />}<br /><br />- (void)awakeFromNib<br />{<br />&nbsp; &nbsp; NSString *path=0;<br />&nbsp; &nbsp; op = [[NSMutableString alloc] init];<br /><br />&nbsp; &nbsp; path = [[NSBundle mainBundle]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  pathForResource:@&quot;Evaluator&quot; ofType:@&quot;&quot;];<br /><br />&nbsp; &nbsp; toPipe&nbsp;  = [NSPipe pipe];<br />&nbsp; &nbsp; fromPipe = [NSPipe pipe];<br /><br />&nbsp; &nbsp; toEvaluator&nbsp;  = [toPipe fileHandleForWriting];<br />&nbsp; &nbsp; fromEvaluator = [fromPipe fileHandleForReading];<br /><br />&nbsp; &nbsp; evaluator = [ [NSTask alloc] init];<br />&nbsp; &nbsp; [evaluator setLaunchPath:path];<br /><br />&nbsp; &nbsp; [evaluator setStandardOutput:fromPipe];<br />&nbsp; &nbsp; [evaluator setStandardInput:toPipe];<br />&nbsp; &nbsp; [evaluator launch];<br /><br />}<br /><br />@end<br />
    
  • BruBru Membre
    18:56 modifié #6
    C'est quoi ton "Evaluator" qui se trouve apparemment dans les ressources du bundle de ton appli ?

    .
  • elfelf Membre
    18:56 modifié #7
    2° ya plein d'erreures d'optimisation, mais je passe.
        ensuite, je crois que tu as pas compris le fonctionnement de OCPlot. L'analyseur marche tout le temps en arriere plan. Pas episodiquement.
    Regarde ca : http://examples.oreilly.com/buildcocoa/buildcocoa_examples.sit dans les dossiers 10 à  14 ya exactment ce que tu veux faire. OCPlot est en parti inspiré de ca.
    Voili voilou.


    Ne t'en fais pas je l'ai bien compilé et inclus dans le bundle


  • Dans ton code, il y a un léger bug dans le chemin de ta commande unix.


    De toute façon, basiquement, l'utilisation de NSTask pour lancer une commande unix devrait à  peu près suivre cet exemple :



    {
        NSString *expression, *resultat;
        NSTask *task;
        NSPipe *out;
        NSData *data;

        expression=@2+3;

        // création des objets relatifs à  la tâche
        task=[[NSTask alloc] init];
        out=[NSPipe pipe];

        // initialisation de la tâche
        [task setLaunchPath:@/bin/expr];
        [task setStandardOutput:[out fileHandleForReading]];
        [task setStandardError:[out fileHandleForReading]];
        [task setArguments:[NSArray arrayWithObjects:expression, nil]];

        // exécution de la commande
        [task launch];

        // récupération du résultat de la commande
        data=[[out fileHandleForReading] availableData];
        resultat=[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

        // affichage du résultat
        NSLog(@%@ = %@", expression, resultat);

        // nettoyage
        [resultat release];
        [task release];
    }

    Faut vérifier le chemin de la commande expr (un petit [tt]where expr[/tt] dans le terminal pour récupérer le chemin).


    A partir de cet exemple, 1000 choses peuvent être déclinées comme :

    - lecture du résultat en background (seulement pour les commandes renvoyant de très gros résultats et sur un long moment)

    - utilisation de pipe au lieu de fileHandle pour les stdin/stdout/stderr.

    - etc...


    .

     




    Alors ça, si c'est pas du déterrage de post, je ne m'y connais pas  :D


    Bon j'ai un souci avec ce code qui me fait une roue de la mort... Sauf si je commente la ligne :



    data=[[out fileHandleForReading] availableData];

    Mais du coup mon résultat ne s'affiche pas dans ma Console (logique)...


    J'imagine que la syntaxe a dû changer depuis tout ce temps... Pourriez-vous me faire un petit update svp histoire que je parte sur de bonnes bases ?


    Merci par avance 

Connectez-vous ou Inscrivez-vous pour répondre.