سؤال

وأنا باستخدام نمط المفرد في عدة أماكن في التطبيق، وأنا اتلقى أخطاء تسرب الذاكرة من clang عند تحليل التعليمات البرمجية.

static MyClass *_sharedMyClass;
+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      [[self alloc] init];
  }
  return _sharedMyClass;
}

// clang error: Object allocated on line 5 is no longer referenced after this point and has a retain count of +1 (object leaked)

وأنا باستخدام هذه الإعدادات لscan-build:

وscan-build -v -v -v -V -k xcodebuild

وأنا واثق تماما أن التعليمات البرمجية في المفرد على ما يرام - بعد كل شيء، انها نفس الرمز المشار إليها هنا على تجاوز المكدس وكذلك في الوثائق أبل - ولكن أود أن الحصول على تحذير تسرب الذاكرة تسويتها حتى بلدي المسح والبناء يعود النجاح.

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

المحلول

وقد أكون كونها كثيفة للغاية، ولكن بالتأكيد خطك 5

[[self alloc] init];

ويخصص كائن من التي تحتوي على نوع الطبقة، وعلى الفور يلقي به بعيدا؟ هل لا تريد

_sharedMyClass = [[self alloc] init];

نصائح أخرى

وأبل منذ قامت بتحديث لها <لأ href = "http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974 -CH4-SW32 "يختلط =" نوفولو noreferrer "> أوصى كود المفرد لتمرير محلل ثابت:

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedManager] retain];
}

والآن +sharedManager يدعو -allocWithZone: فائقة ويعين عودة -init، و-allocWithZone: والمفرد ويعود مجرد sharedInstance الاحتفاظ بها.

وتحرير:

لماذا تحتفظ في + allocWithZone:؟

و+ allocWithZone: يتم تجاوز لشخص ما باستخدام MyGizmoClass يمكن التحايل على المفرد عن طريق الاتصال [[MyGizmoClass الوك] الحرف الأول] بدلا من [MyGizmoClass sharedManager]. لقد احتفظوا بها لأنه من المتوقع دائما للعودة كائن مع الاحتفاظ عدد من +1 + الوك.

وكل دعوة إلى + الوك ينبغي أن يكون متوازنا مع -release أو -autorelease، وذلك دون الاحتفاظ في + allocWithZone :، يحتمل أن يمكن deallocated على سبيل المثال المشتركة من تحت مستخدمين الآخرين.

وقد تكون مهتمة في بسيط، أسلوب واحد، GCD المستندة إلى تنفيذ المفرد (وبالتالي 10.6+ فقط) نشر على <لأ href = "http://www.mikeash.com/؟page=pyblog/friday -qa-2009-10-02 الرعاية والتغذية من بين singletons.html "يختلط =" نوفولو noreferrer "> الموقع مايك الرماد :

+ (id)sharedFoo
{
    static dispatch_once_t pred;
    static Foo *foo = nil;

    dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
    return foo;
}

وأنت يتم الرجوع self في أسلوب فئة! لا لا كبيرة! ثانيا، كنت تتصل [[self alloc] init] ومجرد رمي المثيل. يجب تعيين المرجع المفرد في أسلوب فئة، وليس في init مثل أنا على التخمين تقومون به. بعد ذلك، ليس هناك ما يضمن الحقيقي سيتم تهيئة إلى الصفر أن _sharedMyClass. يجب تهيئة صراحة إلى nil.

static MyClass *_sharedMyClass = nil;

+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      _sharedMyClass = [[MyClass alloc] init];
  }
  return _sharedMyClass;
}

وأيضا ربما كان لديك هذا في وجود جدا ...

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;  // assignment and return on first allocation
        }
    }
    return nil; // on subsequent allocation attempts return nil
}

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

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