2010-11-17 6 views
0

У меня есть метод:Проблема с управлением памятью в Objective-C

- (void)setName:(ModelClass *)model { 

    [model release]; 
    ModelClass *tmp = [[[ModelClass alloc] initWithId:@"New"] autorelease]; 
    model = [tmp retain]; 

    NSLog([NSString stringWithFormat:@"Gia tri trong la %@",model.modelClassId]); 

} 

и

- (void)viewDidLoad { 

    [super viewDidLoad]; 

    ModelClass *tmp3 = [[ModelClass alloc] initWithId:@"Old"]; 

    [self setName:tmp3]; 

    ModelClass *tmp4 = [[ModelClass alloc] initWithId:@"Old"]; 
    ModelClass *tmp5 = [[ModelClass alloc] initWithId:@"Old"]; 
    ModelClass *tmp6 = [[ModelClass alloc] initWithId:@"Old"]; 
    ModelClass *tmp7 = [[ModelClass alloc] initWithId:@"Old"]; 

    NSLog(tmp3.modelClassId); 


} 

Он работает нормально. Но когда я пишу:

- (void)setName:(ModelClass *)model { 

     ModelClass *tmp = [[[ModelClass alloc] initWithId:@"New"] autorelease]; 
     [model release]; 
     model = [tmp retain]; 

     NSLog([NSString stringWithFormat:@"Gia tri trong la %@",model.modelClassId]); 

    } 

это ломает мое приложение. Кто-нибудь может объяснить мне, какая разница между этими двумя случаями?

+1

Ваш код ничего не сделал бы. Чего вы пытаетесь достичь именно? Проблема может быть в ModelClass, поэтому, если вы можете показать нам код, который это поможет. – tia

ответ

2

В вашей реализации setName: есть фундаментальная ошибка, и вам просто удавалось выяснить, что это было неправильно, когда вы перемещали некоторые строки.

При назначении нового значения model в методе setName: вы фактически не изменяя ссылку вы прошли в. Подумайте model в качестве локальной переменной функции (так как это в основном то, что это такое). Никакие изменения, внесенные вами в значение этого указателя, не будут видны при завершении метода. Однако вы можете изменить то, на что оно указывает. И вы это сделаете, потому что вы это release. Ваш setName: код в основном эквивалентно следующему:

- (void)setName:(ModelClass *)model { 
    Model* otherModel = model; 
    [model release]; 
    ModelClass *tmp = [[[ModelClass alloc] initWithId:@"New"] autorelease]; 
    otherModel = [tmp retain]; 
    NSLog([NSString stringWithFormat:@"Gia tri trong la %@", otherModel.modelClassId]); 
} 

Что такое же, как:

- (void)setName:(ModelClass *)model { 
    // Release the `ModelClass` passed in. 
    [model release]; 

    // Create a new object, put in in the autorelease pool, then retain it one 
    // extra time (causing it to leak). NSLog it's modelClassId. 
    ModelClass *tmp = [[[ModelClass alloc] initWithId:@"New"] autorelease]; 
    otherModel = [tmp retain]; 
    NSLog([NSString stringWithFormat:@"Gia tri trong la %@", tmp.modelClassId]); 
} 

Таким образом, в свете того факта, ваш другой метод (с дополнительными TMP объектов, удаленных) делает это:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    // Create a new `ModelClass` instance. 
    ModelClass *tmp3 = [[ModelClass alloc] initWithId:@"Old"]; 

    // Send `tmp3` to `setName:` therefore releasing it. Since `tmp3` was the only 
    // reference, the instance has been deallocated. 
    [self setName:tmp3]; 

    // Attempt to NSLog a member/property of a deallocated object, causing 
    // undefined behavior. 
    NSLog(tmp3.modelClassId); 
} 
0

Вам необходимо прочитать Memory Management Rules. Обратите внимание на бит, выделенный жирным шрифтом:

Вы только выпускаете или авторизуете свои объекты.

У вас есть собственные объекты, которые вы сохраняете или создаете с помощью alloc, new или метод, содержащий «копию».

Так что, глядя на объект под названием model в вашем методе setName:, он был передан как параметр. Вы не сохранили его (в пределах setName:), так что вы не должны его выпускать. Это причина вашего краха.

Вы сначала выделите объект на tmp3, затем вы вызываете setName: с tmp3 в качестве параметра. Это освобождает tmp3, поэтому он больше не указывает на действительный объект. Тот факт, что вы назначили model внутри метода, не имеет значения. Objective-C передает указатель по значению, поэтому указатель tmp3 не затрагивает ничего в setName: хотя объект, на который указывает он, теперь исчез.

Затем вы попадаете в NSLog, tmp3 является обвисшим указателем, поэтому наиболее вероятный результат отправки сообщения ему (как и вы) - это сбой. В исходной реализации setName: вы ударили правильный результат, потому что новый созданный вами объект повторно использовал память, освобожденную объектом tmp3.

Смежные вопросы