title: Common multithreading mistakes beginners make on iPhone
body: <p>I just introduced multithreading into my app JUST to get a silly UIActivityIndicatorView to work. Well, the activity indicator works, alright -- but now my app crashes sometimes, and sometimes it doesn't -- under otherwise controlled conditions... I need to figure this out but don't know where to start looking...</p>
  
  <p>So, what are some common mistakes beginners often make with multithreading on the iPhone? Please be specific in your answers. Thanks for your time. </p>
  
  <p><strong>UPDATE</strong>: I added my problematic source for reference.</p>
  
  <pre><code>//--------------------Where the multithreading starts------------------------
  
  
  -(IBAction)processEdits:(id)sender
  {
          //Try to disable the UI to prevent user from launching duplicate threads
      [self.view setUserInteractionEnabled:NO];
  
          //Initialize indicator (delcared in .h)
      myIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(155, 230, 20, 20)];
      myIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite;
      [self.view addSubview:myIndicator];
      [self.view bringSubviewToFront:myIndicator];
      [myIndicator startAnimating];
  
  
      //Prepare and set properties of the NEXT modal view controller to switch to
      controller = [[EndViewController alloc] initWithNibName:@"EndViewController" bundle:nil];
  
      controller.delegate = self;
  
      [self performSelectorInBackground:@selector(threadWork:) withObject:nil];
  
  
  }
  
  
  
  //-----------------------------THE THREAD WORK--------------------------------
  
  
  -(IBAction)threadWork:(id)sender{
  
      NSAutoreleasePool * pool;
      NSString *          status;
  
      pool = [[NSAutoreleasePool alloc] init];
      assert(pool != nil);
  
  
          //The image processing work that takes time
      controller.photoImage = [self buildPhoto];
  
      //Stop the UIActivityIndicatorView and launch next modal view
      [self performSelectorOnMainThread:@selector(stopSpinner:)withObject:nil waitUntilDone:NO];
  
      [pool drain];
  
  
  }
  
  
  
  
  //-------------------Most of the WORKLOAD called in above thread ------------------------
  
  
  
  -(UIImage*)buildPhoto
  {
      /* 
         This is the work performed in the background thread. Process photos that the user has edited and arrange them into a UIView to be finally flattened out into a new UIImage. Problem: UI usually changes for some reason during this work.
         */
  
      UIView* photoContainerView = [[UIView alloc] initWithFrame:CGRectMake(0,0,975,1300)];
      photoContainerView.backgroundColor = [UIColor whiteColor];
      UIImage* purikuraFlattened;
      int spacerX = 10;
      int spacerY = 10;
  
      switch (myPattern) {
  
          case 0:
  
              photoContainerView.frame = CGRectMake(0, 0, 320, 427);
              layoutSingle = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x,photoContainerView.frame.origin.y,320,427)];
              [photoContainerView addSubview:layoutSingle];
              layoutSingle.image = editPhotoData1;
  
              break;
  
  
          case 1:
  
              layoutAimg1 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX, photoContainerView.frame.origin.y+spacerY, 427, 320)];
              layoutAimg2 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX+427, photoContainerView.frame.origin.y+spacerY, 427, 320)];
              layoutAimg3 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX, photoContainerView.frame.origin.y+spacerY+320, 427, 320)];
              layoutAimg4 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX+427, photoContainerView.frame.origin.y+spacerY+320, 427, 320)];
              layoutAimg5 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX, photoContainerView.frame.origin.y+spacerY+(320*2), 427, 320)];
              layoutAimg6 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX+427, photoContainerView.frame.origin.y+spacerY+(320*2), 427, 320)];
              layoutAimg7 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX, photoContainerView.frame.origin.y+spacerY+(320*3), 427, 320)];
              layoutAimg8 = [[UIImageView alloc] initWithFrame:CGRectMake(photoContainerView.frame.origin.x+spacerX+427, photoContainerView.frame.origin.y+spacerY+(320*3), 427, 320)];
  
              [photoContainerView addSubview:layoutAimg1];
              [photoContainerView addSubview:layoutAimg2];
              [photoContainerView addSubview:layoutAimg3];
              [photoContainerView addSubview:layoutAimg4];
              [photoContainerView addSubview:layoutAimg5];
              [photoContainerView addSubview:layoutAimg6];
              [photoContainerView addSubview:layoutAimg7];
              [photoContainerView addSubview:layoutAimg8];
  
  
              if(myShots == 1){
  
              rotPhoto1 = [self rotateImage:editPhotoData1.size:editPhotoData1];
  
                  layoutAimg1.image = rotPhoto1;
                  layoutAimg2.image = rotPhoto1;
                  layoutAimg3.image = rotPhoto1;
                  layoutAimg4.image = rotPhoto1;
                  layoutAimg5.image = rotPhoto1;
                  layoutAimg6.image = rotPhoto1;
                  layoutAimg7.image = rotPhoto1;
                  layoutAimg8.image = rotPhoto1;
  
  
  
              }else if(myShots == 2){
  
  
              rotPhoto1 = [self rotateImage:editPhotoData1.size: editPhotoData1];
              rotPhoto2 = [self rotateImage:editPhotoData2.size: editPhotoData2];
  
                  layoutAimg1.image = rotPhoto1;
                  layoutAimg2.image = rotPhoto2;
                  layoutAimg3.image = rotPhoto2;
                  layoutAimg4.image = rotPhoto1;
                  layoutAimg5.image = rotPhoto1;
                  layoutAimg6.image = rotPhoto2;
                  layoutAimg7.image = rotPhoto2;
                  layoutAimg8.image = rotPhoto1;
  
  
              }else if(myShots == 4){
  
                  rotPhoto1 = [self rotateImage:editPhotoData1.size: editPhotoData1];
                  rotPhoto2 = [self rotateImage:editPhotoData2.size: editPhotoData2];
                  rotPhoto3 = [self rotateImage:editPhotoData3.size: editPhotoData3];
                  rotPhoto4 = [self rotateImage:editPhotoData4.size: editPhotoData4];
  
                  layoutAimg1.image = rotPhoto1;
                  layoutAimg2.image = rotPhoto2;
                  layoutAimg3.image = rotPhoto3;
                  layoutAimg4.image = rotPhoto4;
                  layoutAimg5.image = rotPhoto1;
                  layoutAimg6.image = rotPhoto2;
                  layoutAimg7.image = rotPhoto3;
                  layoutAimg8.image = rotPhoto4;
  
  
              }
              break;
  
        }
  
  
      UIGraphicsBeginImageContext(photoContainerView.bounds.size);
      [purikuraContainerView.layer renderInContext:UIGraphicsGetCurrentContext()];
      photoFlattened = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext(); 
  
  
      NSEnumerator *enumerator = [[photoContainerView subviews] objectEnumerator];
      id object;
  
      while ((object = [enumerator nextObject])) {
  
          [object removeFromSuperview];
  
      }
  
  
      [photoContainerView release];
  
      photoContainerView = nil;
  
      if(rotPhoto1 != nil){
      [rotPhoto1 release];
          rotPhoto1 = nil;
      }
      if(rotPhoto2 != nil){
      [rotPhoto2 release];
      rotPhoto2 = nil;
      }
      if(rotPhoto3 != nil){
      [rotPhoto3 release];
      rotPhoto3 = nil;
      }
      if(rotPhoto4 != nil){
      [rotPhoto4 release];
      rotPhoto4 = nil;
      }
  
      if(rotPhotoSm1 != nil){
      [rotPhotoSm1 release];
      rotPhotoSm1 = nil;
      }
      if(rotPhotoSm2 != nil){
      [rotPhotoSm2 release];
      rotPhotoSm2 = nil;
      }
      if(rotPhotoSm3 != nil){
      [rotPhotoSm3 release];
      rotPhotoSm3 = nil;
      }
      if(rotPhotoSm4 != nil){
      [rotPhotoSm4 release];
      rotPhotoSm4 = nil;
      }
  
      return photoFlattened;
  
  }
  
  
  
  //-----------------------------STOP THE UIACTIVITYINDICATORVIEW---------------------
  
  
  
  -(IBAction)stopSpinner:(id)sender
  {
  
      [self.view setUserInteractionEnabled:YES];
      [myIndicator stopAnimating];
      [myIndicator release];
      myIndicator = nil;
  
      if(myPattern == 0){
          NSLog(@"SINGLE-SHOT MODE");
          controller.isSingleShot = TRUE;
  
      }else{
  
          NSLog(@"MULTI-SHOT MODE");
          controller.isSingleShot = FALSE;
  
      }
  
      controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
      [self presentModalViewController:controller animated:YES];
  
      [controller release];
  
      [allStamps removeAllObjects];
      [imageFrames removeAllObjects];
  
  
      switch (myShots) {
          case 1:
              [editPhotoData1 release];
              break;
  
          case 2:
              [editPhotoData1 release];
              [editPhotoData2 release];
              break;
  
          case 4:
              [editPhotoData1 release];
              [editPhotoData2 release];
              [editPhotoData3 release];
              [editPhotoData4 release];
              break;
  
      }
  
          /* This is the edited photo that has been onscreen. Processing is now done so it is okay to release it. The UI should be updated and now have a blank, black background instead of the image.
  */
          editedPhoto.image = nil;
      [editedPhoto release];
      editedPhoto = nil;
  
  
  }
  </code></pre>