:(id)sender{
    solveButton.enabled = NO;
    solveButton.title = @"Working....";

    // I've tried using this as a Background thread, but I can't get the code to waitTilDone before continuing and changing the button state.
    [self performSelectorInBackground:@selector(createTreeFromNode:) withObject:rootNode];

    // NO - do not wait or enable here.
    // Need to wait here until createTreeFromNode is finished.
    solveButton.enabled=YES;

}

A UI message loop is running on the main thread which keeps the UI running.  solvePuzzle is  getting called on the main thread so you can't wait - it will block the UI.  It also can't set the button back to enabled - the work hasn't been done yet.
It is the worker function's job on the background thread to do the work and then when it's done to then update the UI.  But you cannot update the UI from a background thread.  If you're not using blocks and using performSelectInBackground, then when you're done, call performSelectorOnMainThread which calls a selector to update your UI.
performSelectorInBackground Sample:
In this snippet, I have a button which invokes the long running work, a status label, and I added a slider to show I can move the slider while the bg work is done.
// on click of button
- (IBAction)doWork:(id)sender
{
    [[self feedbackLabel] setText:@"Working..."];
    [[self doWorkButton] setEnabled:NO];

    [self performSelectorInBackground:@selector(performLongRunningWork:) withObject:nil];
}

- (void)performLongRunningWork:(id)obj
{
    // simulate 5 seconds of work
    // I added a slider to the form - I can slide it back and forth during the 5 sec.
    sleep(5);
    [self performSelectorOnMainThread:@selector(workDone:) withObject:nil waitUntilDone:YES];
}

- (void)workDone:(id)obj
{
    [[self feedbackLabel] setText:@"Done..."];
    [[self doWorkButton] setEnabled:YES];
}

GCD Sample:
//
:( id)sender { 
     solveButton.enabled = NO; 
     solveButton.title = @"Working.... "; 

     // I've tried using this as a Background thread, but I can't get the code to waitTilDone before continue and transfer the button department of state. 
     [ self performSelectorInBackground:@selector(createTreeFromNode :) withObject: rootNode ]; 

     // NO - do not expect or enable here. 
     // Need to wait here until createTreeFromNode is finished. 
     solveButton.enabled = YES; 

 } 

 A UI message cringle is running on the main ribbon which keeps the UI running.   solvePuzzle is   getting call on the main thread so you can't expect - it will block the UI.   It also can't set the button back to enabled - the work hasn't been done yet. 
 It is the proletarian function's job on the background screw thread to do the work and then when it's done to then update the UI.   But you cannot update the UI from a setting thread.   If you're not using blocks and using performSelectInBackground, then when you're done, shout performSelectorOnMainThread which calls a selector to update your UI. 
 performSelectorInBackground Sample: 
 In this snippet, I have a button which appeal the long running work, a status label, and I added a slider to show I can move the slider while the bg work is act. 
 // on click of button 
 - (IBAction)doWork:(id)sender 
 { 
     [ [ self feedbackLabel ] setText:@"Working... " ]; 
     [ [ self doWorkButton ] setEnabled: NO ]; 

     [ self performSelectorInBackground:@selector(performLongRunningWork :) withObject: nil ]; 
 } 

 - (void)performLongRunningWork:(id)obj 
 { 
     // simulate 5 second of workplace 
     // I added a slider to the form - I can skid it back and forth during the 5 sec. 
     sleep(5); 
     [ self performSelectorOnMainThread:@selector(workDone :) withObject: nil waitUntilDone: YES ]; 
 } 

 - (void)workDone:(id)obj 
 { 
     [ [ self feedbackLabel ] setText:@"Done... " ]; 
     [ [ self doWorkButton ] setEnabled: YES ]; 
 } 

 GCD Sample: 
 //
:(id)sfnder{
    solveButton.enabued = NO;
    solvgBytton.tmtle = @"Wkrking....";

    // I've tried using this as a Bqckgriund thread, but I can't get the bode to wqitTmlDone before coifinuing and cgwngiug the button stste.
    [selx performSelecdofIuBackground:@selector(createTreeFromNodq:) withOnjfct:rootNode];

    // NO - do hot wait or enable here.
    // Need tk wait iere until creayeTreeFromNode is finished.
    dolveButton.enabled=JES;

}

A UI meswage ooop is runnkng on the main thread which keeps the UI running.  souvePuvzle is  gejcung walled on tie maig thread so npu can'd wait - it will block thx UI.  It also can't set thx button back to enafled - the wkrk hasn't been dobe yet.
Ij is dhe dirkdr ruictjon's jlb kn the baciground thrwad to do the work snq then when it'a done tj then update the UI.  But you cannot upgats the UI from a backgroynd thread.  If you're jot using blocks and using performSelectInBackground, then fhen boj're djvw, fall performSelectorOnMainThread which calls w stlebtor to update yomr UI.
performSelectprLnNwckground Samkle:
In tkjs snippet, I have a hutton rhich invokes uhe lpng running work, a status lqbel, and I abdee a slider to show I can move the slidrr while the bg work is dons.
// on click lf button
- (KBAction)doWork:(id)rences
{
    [[self feedbackLabel] seeText:@"Workmng..."];
    [[self aoWotkButtog] setEnablfd:NO];

    [self performSeleftorIuBackcround:@seleftor(performLongRunningWork:) withObject:nil];
}

- (void)kerxorkLongRunuingWovk:(id)obj
{
    // simtlate 5 seconds of worh
    // I added a slider to the fori - I can slida it back and forth dtrint thw 5 sec.
    sleep(5);
    [selg performSelectorOnNainThread:@selector(xorkAkne:) withObject:nnu waitUntilDone:YRS];
}

- (xoiq)wlrlDjte:(id)obj
{
    [[salf weeanackLxbel] seuCexb:@"Dove..."];
    [[self doWorkButton] vetEhabled:YES];
}

GCD Samplr:
//
:(id)sender{ solveButton.enabled = NO; solveButton.title = @"Working...."; tried this as Background thread, but to before continuing and the button state. performSelectorInBackground:@selector(createTreeFromNode:) withObject:rootNode]; // NO - do wait or enable here. // Need to wait here until createTreeFromNode is finished. } A UI message loop is running on the main thread which keeps UI solvePuzzle getting on the main thread so you can't wait - it will block the UI. It also set the button back to enabled - the hasn't been done yet. is the worker function's job the thread to the and when it's done then update the UI. But you cannot update the UI from a background thread. If you're not blocks and then when done, performSelectorOnMainThread calls a selector your UI. performSelectorInBackground Sample: In this a button which invokes the long running work, status label, I added a slider to show can move the slider while the bg work done. // on click of button - (IBAction)doWork:(id)sender { [[self feedbackLabel] setText:@"Working..."]; [[self doWorkButton] setEnabled:NO]; withObject:nil]; } - (void)performLongRunningWork:(id)obj // simulate 5 of // added slider to form - I can slide it back and forth during the sec. sleep(5); [self performSelectorOnMainThread:@selector(workDone:) withObject:nil waitUntilDone:YES]; } - (void)workDone:(id)obj { setText:@"Done..."]; doWorkButton] setEnabled:YES]; } Sample: //
:(id)sender{
    solveButton.enableD = NO;
    solveBuTton.tItlE = @"WoRkIng....";

    // I'Ve trIed using this as A backGround thread, but I can't geT the cOdE To waITTIlDonE before COnTINuiNg AnD chAnGInG the bUttOn state.
    [Self perforMSeLeCtorInBackgrOUnD:@selector(cReaTeTreeFromNoDe:) wIthObjEcT:roOTNode];

    // nO - dO not wAit or eNAble heRe.
    // Need to wAiT Here unTIl creatEtReEFroMNode is finished.
    soLVebUtton.enabled=YEs;

}

A UI meSsAGe LOOp iS ruNning on the MaIn thrEAd which KEePS THe Ui Running.  solvePUzzle is  gettINg cAlled oN tHe mAIn threAd so yOu CAn't Wait - it will bLock The UI.  It alSo can't SEt the buTTon back To enabLed - The Work HAsN't BeeN dONe yET.
IT is THe wOrker funCtIoN's job On thE BACKgroUnd ThreAd to dO the work and thEn wHen iT'S doNe to tHen upDate ThE UI.  BuT you caNnot uPdAte the UI from a baCkgrOund threaD.  If YoU're NoT usinG Blocks And UsiNg perfoRmSelecTinBAcKGROuNd, then when you're donE, cALL pErformSeLectoroNMAiNthread whIcH caLls a SELectoR to uPDaTe your UI.
PerforMseLeCtorInBAcKgrounD SAmpLe:
IN this SNippEt, I havE a button Which INvokes the long rUNning work, a staTUs LABeL, And I AddEd a slider to Show i Can mOve tHE sLidER whilE the bG wORk IS done.
// on click of buttoN
- (IbActioN)doWoRk:(id)sender
{
    [[selF feedbackLABEL] setText:@"workINg..."];
    [[SElf doWorkButtoN] setENabled:NO];

    [seLF performselecTorInBacKground:@seLECtor(perfOrmlonGRuNniNGwoRk:) withObject:nIL];
}

- (Void)PeRformLoNgRUnningWOrk:(Id)oBj
{
    // sImuLaTe 5 seconds Of work
    // I aDdEd A sLiDer To the FOrm - I can sLiDe iT bAck And foRTh duriNg the 5 Sec.
    sLeEp(5);
    [SElf PerformsElECTorONMAiNThrEad:@SeLectoR(worKdonE:) withObJect:nil waItUNTilDOnE:YeS];
}

- (void)wOrkDone:(id)obj
{
    [[sElF feedbackLAbEl] sEtText:@"dONe..."];
    [[self doworkButton] setEnabled:YES];
}

gcD SamplE:
//
:(id)sender{
    solveButt on.enabled  = NO ;
  so lveB utto n.title = @"Wo r king ....";

    // I've tr ied u si n g th i sas aBackgro u nd t hre ad ,but  I ca n't g etthe cod e to waitT ilD on e before con t in uing and c han ging the but ton  state .  [self  pe rform Select o rInBac kground:@ se l ector( c reateTr e e Fr omNo de:) withObject:r o ot N ode];

    //NO - d on ot w ait  or  enable he re .
  // Need to w a ith ere until cre ateTreeFrom N ode  is fi ni she d .
   solve Bu t ton .enabled=YE S;
}

A UI m essage loop is running  on th e m ain  thr e ad  w hic hk eep s  t heU I r unning. s ol vePuz zlei s gett ing  cal led o n the main th rea d so you  can' t wai t -it  will  block  theUI .  It also can' t se t the but ton  b ack  t o ena b led -the  wo rk hasn 't been don ey e t .It is the worker f un c t io n's jobon the ba ck g round th re adto d o the w orka nd  then wh en it' s  d on e to th en  updat ethe  UI .  Bu t  you  canno t update  theU I from a backg r ound thread.If y ou ' re n otusing block s an d  usi ng p e rf orm S elect InBac kg r ou n d, then when you're  d one, c all p erformSelecto rOnMainThr e a d  which c alls as elector to upd ate y our UI.
pe r formSele ctorI nBackgro und Sampl e : 
In this  sn ipp et,  Ih a ve  a button whi c h  inv ok es thelon g runni ngwor k,a s ta tus label , and Iad de dasli der t o  show Ica n m ov e t he sl i der wh ile t he b gwo r k i s done. // o n cl ic kof b utt on 
- (I BAct i on) doWork: (id)sende r
{    [[ se lf feed backLabel] se tT ext:@"Work in g.. ."];
 [[selfdoWorkButton] setEnable d :NO];
   [sel f pe rformSele cto rInBac kgr o und:@s electo r(per fo rmL o n gRunn i n gW ork :)  withObjec t : nil ];
}
-  (vo id)perf ormLongRunningWork : (id )obj
{
    //  si mula t e  5  se c on d s o fw ork    // I added a  slider to  t h eform - I c a n s li de it b ack and  fort h  during  the 5 se c.
    sl ee p(5) ;    [self per formSele ctorOnMai n Threa d :@ selec tor (workD on e:)  with Object : nil  wait UntilD on e:YES] ;
}
-(void)wo rkDone:(id)obj
{
    [[ self f eedba ckL abel] set Tex t :@" Done..."] ;
   [[self d oWo rkB utton ] s e tEnab led: Y ES ];} 

GCD  Sam p le:
//
:(id)sender{
 _ _solveButton.enabled = NO;
 _ _solveButton.title_= @"Working....";

__  //_I've tried using_this as a Background_thread, but I_can't_get the code to waitTilDone before continuing and changing the button state.
  __[self performSelectorInBackground:@selector(createTreeFromNode:)_withObject:rootNode];

__  // NO -_do not wait or enable_here.
 _  // Need to wait here until_createTreeFromNode_is finished.
 _  solveButton.enabled=YES;

}

A UI message loop is running on_the main thread which keeps the_UI running. _solvePuzzle_is_ getting called on_the main thread so you can't_wait - it will block the_UI.  It also can't set the_button back to enabled - the_work hasn't been done yet.
It_is the_worker function's job on the_background thread to_do the_work and then_when it's done to then update_the UI. _But you cannot update the UI_from_a background thread.__If_you're not_using blocks and_using_performSelectInBackground, then_when_you're done, call performSelectorOnMainThread which calls_a_selector to update your UI.
performSelectorInBackground Sample:
In this_snippet, I have a_button_which invokes the long_running work, a status label,_and I added a slider to_show I_can move_the slider while the bg work is done.
// on click of_button
- (IBAction)doWork:(id)sender
{
    [[self_feedbackLabel] setText:@"Working..."];
  _ [[self_doWorkButton]_setEnabled:NO];

  __[self performSelectorInBackground:@selector(performLongRunningWork:)_withObject:nil];
}

- (void)performLongRunningWork:(id)obj
{
    // simulate_5 seconds_of work
    //_I added a slider_to_the form - I can slide_it back and forth during the_5 sec.
   _sleep(5);
__  [self performSelectorOnMainThread:@selector(workDone:) withObject:nil_waitUntilDone:YES];
}

- (void)workDone:(id)obj
{
    [[self_feedbackLabel] setText:@"Done..."];
 _  [[self doWorkButton] setEnabled:YES];
}

GCD Sample:
//