Frage

Ich stellte nur GERADE Multithreading in meine app eine dumme UIActivityIndicatorView zur Arbeit zu kommen. Nun, die Aktivitätsanzeige funktioniert, in Ordnung - aber jetzt meine app stürzt manchmal und manchmal nicht - unter sonst kontrollierten Bedingungen ... Ich brauche diese, um herauszufinden, aber nicht wissen, wo zu Beginn der Suche ...

Also, was sind einige häufige Fehler Anfänger oft mit Multithreading auf dem iPhone machen? Bitte spezifisch in Ihren Antworten. Vielen Dank für Ihre Zeit.

UPDATE . Ich meine problematische Quelle als Referenz hinzugefügt

//--------------------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;


}
War es hilfreich?

Lösung

Diese Frage hat einige gute Ressourcen auf Cocoa Multithreading: " Wo kann ich ein gutes Tutorial auf dem iPhone / Objective c Multithreading finden? "

ich auch sehr empfehlen, die neue Lese Concurrency Programming Guide ( jedoch ignorieren die Blöcke und Dispatch-Warteschlangen, wie Grand Central Dispatch noch nicht verfügbar auf iPhone OS ist iOS 4.0 nur hinzugefügt Blöcke und GCD), weil es ein starkes Argument macht für Strukturen wie NSOperation NSOperationQueue und als alternative zu manuell erzeugten Threads. Für Informationen über manuell erstellt Verknüpfungen, beziehen sich auf die Programming Guide Threading.

Wie RC erwähnt, die größte einzelne Quelle von Abstürzen mit multithreaded Cocoa-Anwendungen ist die gleichzeitige Zugriff auf eine gemeinsam genutzte Ressource. Die @synchronized Richtlinie ist nicht die schnellste, wie spitze out von Colin Wheeler , so dass Sie verwenden NSLock zu schützen Zugriff auf Ihre freigegebenen Ressourcen wollen könnte. Jedoch kann jegliche Art Sperr teuer sein, weshalb ich habe meine Anwendungen über mit einfacher Breite NSOperationQueues für den Zugang zu diesen Ressourcen zu migrieren. Die Leistungsverbesserungen wurden signifikant.

Ein weiterer Problembereich mit Cocoa und Multithreading kommt aus Benutzeroberfläche Updates. Alles UI-Updates in Cocoa muss auf dem Haupt-Thread ausgeführt werden, oder Instabilität führen kann. Wenn Sie einen Hintergrund-Thread eine Berechnung haben durchführen, stellen Sie sicher, zu wickeln, was Methode, um die Benutzeroberfläche in einem -performSelectorOnMainThread:withObject:waitUntilDone: Methodenaufruf aktualisiert.

Andere Tipps

Die wohl häufigste Fehler Anfänger (in jeder Sprache), wenn sie mit Fäden arbeiten für den Zugang zu gemeinsam genutzten Ressourcen wandelbar ohne Wachen / mutexes. Sie schützt Ressourcen wie:

@synchronized(sharedData)
{
   // modify sharedData safely
}

Sie wollen die Menge der Daten zwischen Threads gemeinsam zu begrenzen und wenn sie geteilt werden müssen, bevorzugen unveränderliche Objekte, um Streit durch Synchronisation zu reduzieren.

Themen verwalten ist ein weiterer Ort, wo Probleme auftreten können. Hier ist ein Dokument Bezug auf die Verwendung von Threads im iPhone.

http://developer.apple.com/iphone/library/documentation /cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html .

Ohne Code bereitstellt, denke, es ist niemandes, was mit Ihrer App falsch ist, aber ich würde beginnen mit dafür sorgen, sind Sie richtig die Erstellung und Beendigung des Gewindes sowie Putting besondere Aufmerksamkeit auf alle freigegebenen Ressourcen Verwaltung dieser Thread Versuche zu erreichen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top