ios - هل الرقص الضعيف/القوي هو أمر ضروري حقًا عند الرجوع إلى الذات داخل إتمام غير محتفظ به يتم استدعاءه من مراقب UIViewController؟




objective-c objective-c-blocks (3)

قل لدي الطريقة التالية داخل UIViewController فرعية UIViewController :

- (void)makeAsyncNetworkCall
{
    [self.networkService performAsyncNetworkCallWithCompletion:^{
        dispatch_async(dispatch_get_main_queue(), ^{
                [self.activityIndicatorView stopAnimating];
            }
        });
    }];
}

أعلم أن الإشارة إلى self داخل الكتلة ينتج عنها مثيل UIViewController يتم الاحتفاظ به بواسطة الكتلة. طالما أن performAsyncNetworkCallWithCompletion لا يقوم بتخزين الكتلة في خاصية (أو إيفار) على NetworkService ، فهل أنا على صواب في التفكير في عدم وجود دورة الاحتفاظ؟

أدرك أن هذه البنية أعلاه ستؤدي إلى الاحتفاظ بـ performAsyncNetworkCallWithCompletion حتى انتهاء performAsyncNetworkCallWithCompletion ، حتى إذا تم إصداره بواسطة النظام مسبقًا. ولكن من المحتمل (أو حتى ممكن؟) سيقوم النظام بإلغاء تخصيص UIViewController على الإطلاق ( بعد التغييرات في الطريقة التي يدير بها iOS 6 ذاكرة CALayer تدعم CALayer

إذا كان هناك سبب يجب أن أقوم به "الرقص الضعيف / القوي."

- (void)makeAsyncNetworkCall
{
    __weak typeof(self) weakSelf = self;
    [self.networkService performAsyncNetworkCallWithCompletion:^{
        typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf) {
            return;
        }
        dispatch_async(dispatch_get_main_queue(), ^{
                [strongSelf.activityIndicatorView stopAnimating];
            }
        });
    }];
}

لكنني أجد ذلك قبيحًا بشكل غير معقول وأرغب في تجنبه إذا لم يكن ضروريًا.


أعتقد أن المشكلة هي أن شبكة الخدمات قد تحتفظ بمرجع قوي للكتلة. وربما تحتوي وحدة التحكم في العرض على إشارة قوية إلى الشبكة. لذلك يمكن أن توجد دورة VC-> NetworkService-> block-> VC. ومع ذلك ، في هذه الحالة ، يكون من الآمن عادة افتراض أن الكتلة ستصدر بعد تشغيلها ، وفي هذه الحالة تكون الدورة مكسورة. لذلك ، في هذه الحالة ، ليس من الضروري.

حيث يكون ذلك ضروريًا إذا لم يتم إصدار الكتلة. قل ، بدلاً من أن يكون هناك كتلة يتم تشغيلها مرة واحدة بعد اتصال الشبكة ، لديك كتلة يتم استخدامها كرد اتصال. أي كائن networkService يحافظ على مرجع قوي للكتلة ويستخدمه لجميع عمليات الاسترجاعات. في هذه الحالة ، سيكون للكتلة إشارة قوية إلى VC ، وهذا سيخلق دورة قوية ، لذلك يفضل إشارة ضعيفة.


الجواب ليس بهذه السهولة هنا. أتفق مع إجابة @ Rob ، ولكنها تحتاج إلى شرح إضافي:

  1. يعتبر __weak طريقة آمنة ، لأنه لا يخفى على النفس عند إطلاقه ، مما يعني أنه لن يكون هناك استثناء إذا حدث رد الاتصال لاحقًا عندما يتم تحرير كائن الاتصال بالفعل ، المشار إليه بواسطة كتلة ، مثل برزت UIViewController من المكدس. إضافة إمكانية إلغاء أي نوع من العمليات هو مجرد مسألة النظافة وربما الموارد كذلك. يمكنك أيضًا ، على سبيل المثال ، إلغاء NSURLConnection فقط ، وليس فقط NSOperation الذي يمكن إلغاؤه ، بل يمكنك إلغاء كل ما يتم تنفيذه بشكل غير متزامن NSOperation التي NSOperation .

  2. إذا تم السماح UINavigationController ، UINavigationController أن تصبح القصة معقدة بعض الشيء إذا تم إصدار كائن المتصل مثل UINavigationController بواسطة UINavigationController ولا يزال الحظر يحتفظ به UINavigationController . في هذه الحالة سيتم تنفيذ كتلة رد الاتصال ويفترض أن بعض البيانات سيتم تغييرها بنتائجها. قد يكون ذلك سلوكًا مطلوبًا ، لكن في معظم الحالات لا. لذلك قد يكون إلغاء العملية أكثر أهمية في هذه الحالة ، مما يجعله من الحكمة للغاية في أساليب UINavigationControllerDelegate عن طريق إلغاء المهام غير المتزامنة من المجموعة UINavigationController للتغيير التي توجد إما على UINavigationController ككائن مرتبط أو ككائن UINavigationController .

حفظ الرهان يكون مع الخيار الأول ، بالطبع ، ولكن فقط في حالة عدم رغبتك في استمرار العملية غير المتزامنة بعد رفض كائن المتصل.


لا ، إذا كنت لا تستخدم self.networkService كخاصية كتلة ، فيجب أن تكون على ما يرام