objective c - كتلة عودية والاحتفاظ دورات في أرك




objective-c recursion (2)

EDIT2:

لا. الجواب المقترح حول المكالمات غير المتزامنة . أريد & تحتاج مكالمات متزامنة، كما هو الحال في العادية، دعوة عودية القياسية.

تصحيح:

في حين

__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;

ويجمع دون سابق إنذار أو أخطاء، فإنه فشل في وقت التشغيل مع نول المخزنة في غير آمنة.

ومع ذلك، هذا:

- (void) applyToView: (UIView *) view {

    UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
        return [UIColor colorWithHue: ((CGFloat) index / 255.0f)
                          saturation: 0.5f
                          brightness: 0.5f
                               alpha: 1.0f] ;
    } ;

    void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
        view.backgroundColor = colorForIndex(index) ;
    } ;

    void (^__block recurse_apply)(UIView *, NSInteger) ;

    void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
        applyColors(view, level) ;
        [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
            recurse_apply(subview, 1+level) ;
        }] ;
    } ;

    recurse_apply = apply ;

    apply(view, 0) ;
}

ويجمع دون تحذيرات، ولكن الأهم من ذلك، يعمل في الواقع.

ولكن هذا هو قبيح جدا !

النظر (تلوين التسلسل الهرمي للعرض، لفضح الغرض ...) :

- (void) applyToView: (UIView *) view {

    UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
        return [UIColor colorWithHue: ((CGFloat) (index * 10.0f) / 255.0f)
                          saturation: 0.5f
                          brightness: 0.5f
                               alpha: 1.0f] ;
    } ;

    void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
        view.backgroundColor = colorForIndex(index) ;
    } ;

    void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
        applyColors(view, level) ;
        [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
            apply(subview, 1+level) ;
        }] ;
    } ;

    apply(view, 0) ;
}

أحصل على هذا التحذير:

/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:551:42: Block pointer variable 'apply' is uninitialized when captured by block

إذا قمت بتطبيق الإصلاح المقترح: Maybe you meant to use __block 'apply'

void (^__block apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {

ثم أحصل على: /Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:554:13: Capturing 'apply' strongly in this block is likely to lead to a retain cycle

حاولت طرق مختلفة للعبث مع التعليمات البرمجية والتخلص من تلك التحذيرات

__weak typeof (apply) wapply = apply ;
if (wapply) {
    __strong typeof (wapply) sappy = wapply ;
    wapply(subview, 1+level) ;
}

ولكن الأمور تزداد سوءا، وتحول إلى أخطاء.

انتهى بي الأمر بهذا:

__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;

void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
    applyColors(view, level) ;
    [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
        unsafe_apply(subview, 1+level) ;
    }] ;
} ;

unsafe_apply = apply ;

apply(view, 0) ;

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

ملاحظة تلك الأسئلة سو حول التقاط self وهذه الأسئلة سو ليس لديهم أي إجابة مرضية.


الجواب هو لا.

لا يمكننا أن نبدو أفضل من استخدام التصفيات __block.

__block void(^strawberryFields)();
strawberryFields = ^{ strawberryFields(); };
strawberryFields();

بفضل بيل بومغارنر المادة حول كتل.

تصحيح:

__block __weak void(^strawberryFields)();

ويبدو أن الطريقة المفضلة تحت أرك.


تحتاج إلى التقاط متغير __block ، لأن كتل التقاط المتغيرات غير __block بالقيمة عندما يتم إنشاؤها، ويتم التخصيص بعد إنشاء كتلة.

في أرك، __block متغيرات نوع مؤشر الكائن (عموما جميع المتغيرات ضمنيا __strong ) يتم الاحتفاظ بها من قبل الكتلة. حتى إذا كان كتلة يلتقط متغير __block مشيرا إلى نفسه، فإنه سيتم إنشاء دورة الاحتفاظ. الحل هو أن يكون التقاط إشارة ضعيفة. في إصدارات نظام التشغيل التي تدعم __weak ، يجب استخدام __unsafe_unretained بدلا من __unsafe_unretained .

ومع ذلك، إذا كانت الإشارة الوحيدة إلى الكتلة متغيرة __weak ، لن تكون هناك إشارات قوية إلى الكتلة، مما يعني أنه يمكن إلغاء تخصيصه. من أجل استخدام كتلة، يجب أن يكون إشارة قوية للحفاظ عليه حولها.

لذلك، تحتاج اثنين من المتغيرات، واحدة ضعيفة واحدة قوية. الطريقة الصحيحة للقيام بذلك في أرك هي:

__block __weak void (^weak_apply)(UIView *, NSInteger) ;
void (^apply)(UIView *, NSInteger) ;
weak_apply = apply = ^(UIView * view, NSInteger level) {
    applyColors(view, level) ;
    [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
        weak_apply(subview, 1+level) ;
    }] ;
} ;

apply(view, 0) ;




retain-cycle