أخطاء متعددة القراءة الشائعة التي يرتكبها المبتدئون على iPhone

StackOverflow https://stackoverflow.com/questions/1357108

سؤال

لقد أدخلت للتو قراءة متعددة في تطبيقي فقط للحصول على uiactivityIndicatorView سخيفة للعمل. حسنًا ، يعمل مؤشر النشاط ، على ما يرام - ولكن الآن يتعطل تطبيقي في بعض الأحيان ، وأحيانًا لا يفعل ذلك - في ظل ظروف يتم التحكم فيها بطريقة أخرى ... أحتاج إلى معرفة ذلك ولكن لا أعرف من أين أبدأ البحث ...

لذا ، ما هي بعض الأخطاء الشائعة التي يرتكبها المبتدئون في كثير من الأحيان مع MultiTreading على iPhone؟ يرجى أن تكون محددًا في إجاباتك. شكرا على وقتك.

تحديث: أضفت مصدري الإشكالي للرجوع إليه.

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


}
هل كانت مفيدة؟

المحلول

يحتوي هذا السؤال على بعض الموارد الجيدة على Multithreading Cocoa: "أين يمكنني العثور على برنامج تعليمي جيد على iPhone/Objective C Multiphreading؟"

كما أوصي بشدة بقراءة الجديد دليل برمجة التزامن (ومع ذلك ، تجاهل الكتل وقوائم الإرسال ، حيث أن Grand Central Dispatch لم يكن متاحًا بعد على iPhone OS iOS 4.0 فقط تم إضافة كتل و GCD) ، لأنها تجعل حالة قوية لاستخدام هياكل مثل NSOperation و NSOperationQueue كبديل للخيوط التي تم إنشاؤها يدويًا. للحصول على معلومات حول المواضيع التي تم إنشاؤها يدويًا ، راجع دليل برمجة الخيوط.

كما يذكر RC ، فإن أكبر مصدر منفرد للحوادث مع تطبيقات الكاكاو متعددة مؤشرات الترابط هو وصول متزامن إلى مورد مشترك. ال @synchronized التوجيه ليس الأسرع ، مثل أشار من قبل كولين ويلر, ، لذلك قد ترغب في استخدام NSLock لحماية الوصول إلى مواردك المشتركة. ومع ذلك ، يمكن أن يكون القفل من أي نوع مكلفًا ، وهذا هو السبب في أنني كنت أقوم بترحيل تطبيقاتي إلى استخدام واحد NSOperationQueues للوصول إلى هذه الموارد. كانت تحسينات الأداء كبيرة.

منطقة مشكلة أخرى مع الكاكاو والمتعددات تأتي من تحديثات واجهة المستخدم. يجب أن تتم جميع تحديثات واجهة المستخدم في الكاكاو على الخيط الرئيسي ، أو يمكن أن يؤدي عدم الاستقرار. إذا كان لديك مؤشر ترابط خلفية يقوم بحساب ، فتأكد من لف أي طريقة تحديث واجهة المستخدم في أ -performSelectorOnMainThread:withObject:waitUntilDone: استدعاء الطريقة.

نصائح أخرى

ربما يتيح المبتدئون الأكثر شيوعًا (بأي لغة) عند العمل مع المواضيع ، الوصول إلى الموارد المشتركة القابلة للتغيير دون حراس/موتيكات. تحرس الموارد مثل:

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

سترغب في الحد من كمية البيانات المشتركة بين مؤشرات الترابط ، وإذا كان يجب مشاركتها ، تفضل الكائنات غير القابلة للتغيير من أجل تقليل الخلاف الناجم عن التزامن.

إدارة المواضيع هي مكان آخر يمكن أن تنشأ فيه المتاعب. فيما يلي مرجع مستند خاص باستخدام مؤشرات الترابط في iPhone.

http://developer.apple.com/iphone/library/documentation/cocoa/conceptual/multithReading/creatingthreads/creatingthreads.html.

دون توفير الكود ، فإنه يخمن أي شخص ما هو الخطأ في تطبيقك ، لكنني سأبدأ بالتأكد من أنك تدير بشكل صحيح إنشاء وإنهاء الخيط بالإضافة إلى وضع اهتمام خاص لأي موارد مشتركة يحاول الخيط الوصول إليها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top