استدعاء Dealloc في init؟
-
27-09-2019 - |
سؤال
أنا أكتب إطار عمل ولدي كائن ذو طريقة init مخصصة:
@implementation OSDatabase
@synthesize database;
// MEM
- (void)dealloc {
sqlite3_close(database);
[super dealloc];
}
// INIT
- (id)initWithDatabasePath:(NSString *)path error:(NSError **)error {
if (self = [super init]) {
if (!sqlite3_open_v2([path UTF8String], &database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)) {
error = [NSError errorWithDomain:@"OSDatabaseErrorDomain" code:1 userInfo:nil];
[self dealloc];
return nil;
}
}
return self;
}
@end
هل من الآمن الاتصال dealloc
داخل init
الطريقة إذا حدث خطأ؟ لست متأكدًا من ذلك وإدارة الذاكرة هي واحدة من أهم الأشياء في حياتي.
شكرًا.
المحلول
هل من الآمن استدعاء Dealloc داخل طريقة init إذا حدث خطأ؟
لا الإرسال -release
مثلك في كل مكان آخر. حتى في -init
لا يمكنك ضمان أن عدد الاحتفاظ الحالي هو 1.
لماذا يجب ألا ترسل أبدًا -dealloc
إلا [super dealloc]
في -dealloc
؟ والسبب هو أنه لا يمكنك ضمان أن يكون هناك شيء آخر أيضًا إشارة إلى كائنك ، حتى في كائنك -init
بسبب ال [super init]
قد تختار الاحتفاظ بالكائن.
إذا تم إرجاع الكائن [super init]
لديه عدد الاحتفاظ 1 ، إرسال -release
سيكون له نفس تأثير الإرسال -dealloc
. إذا كان لديه عدد أكبر من 1 ، فإن هناك شيئًا آخر يعتقد أنه يمتلك الكائن ويتركه سيتركه مع مؤشر غير صالح ، لذلك -release
لا يزال الشيء الصحيح الذي يجب القيام به.
هذا ايضا:
while([self retainCount] != 0){[self release];}
من شأنه أن يؤدي إلى حلقة لا حصر لها وهي فكرة فظيعة لعدد من الأسباب. تهم الاحتفاظ بالأشياء لا تنخفض إلى 0. -release
يبدو مثل هذا:
- (id)release
{
if (retainCount == 1)
{
[self dealloc];
}
else
{
retainCount--;
}
}
لذا فإن الحلقة ستقلل من العد إلى 1 ثم استدعاء Dealloc إلى الأبد أو حتى فساد الكومة الذي تسبب في يؤدي إلى خطأ SEG.
بصرف النظر عن عدم الوصول إلى الصفر ، قد يكون الاحتفاظ UINT_MAX
(على سبيل المثال في الأسلاك أو الحرفية الرقمية) والتي تعني العامية "يجب ألا يتم تخصيص هذا الكائن أبدًا". إذا كان عدد الاحتفاظ UINT_MAX
, -release
لن يقلل من ذلك.
نصائح أخرى
لكل مستندات يجب ألا تتصل بمواجهة مباشرة - فقط - فقط [super dealloc]
الطريقة في Dealloc المخصصة الخاصة بك.
أعتقد أن الدعوة release
بدلاً من ذلك ، يجب أن تفعل ما هو متوقع (على الأقل إذا كنت تستخدم طريقة init فقط في نمط التخصيص القياسي).
كما ذكر فلاديمير أنك يجب ألا تتصل أبدًا dealloc
مباشرة. عندما يصل عدد الكائن إلى 0 ، يتصل الكاكاو تلقائيًا dealloc
.