iPhone, передача объекта в метод (ы), управление памятью - PullRequest
0 голосов
/ 23 июля 2010

Я знаю, что на эту тему уже есть много вопросов, но мне это пока не ясно. Итак, что меня все еще интересует, так это то, что если я вызываю метод и передаю ему объект, нужно ли мне тогда сохранять этот объект внутри моего метода, чтобы использовать его там. И если я сохраню это, где я выпущу это. Давайте сделаем немного более сложный пример. Может ли кто-нибудь объяснить, что не так с этим:

NSString *myStr = [[NSString alloc]initWithString:@"Hello"];

myStr = [self modString2:[self modString1:myStr]];
[myStr release];

//These are the methods...

-(NSMutableString*)modString1:(NSString*)str{
 return [[[str stringByAppendingString:@" Mr. Memory"] mutableCopy] autorelease];
}

-(NSMutableString*)modString2:(NSString*)str{
 return [[[str stringByAppendingString:@" How about this?"] mutableCopy] autorelease];
}

Это меня так смущает. Предположим, я создал объект внутри метода:

[self modString:[self createString]];


-(NSString*)createString{
 NSString *string = [NSString stringWithString:@"Hello"];
 return string;
}

-(NSMutableString*)modString:(NSString *)str{
 [str retain];
 NSMutableString *mut = [NSMutableString stringWithString:str];
 return mut;
}

Это было бы правильно? Другое дело: если я скопирую строку из массива в строку вроде:

NSString *str = [NSString alloc[ initWithString:[[arr objectAtIndex:0]copy]]];

Сохраняет ли весь массив или что здесь происходит? Означает ли это, что я должен освободить массив? Я не понимаю Есть ли какие-либо практические ресурсы, кроме яблочных? Я очень хочу это понять ...

Метод не владеет объектом, который передается ему в качестве аргумента ?! Правильно? И мне нужно было бы только сохранить объект в методе, если сам объект является объектом, возвращаемым методом (который был вызван ранее) с автоматическим выпуском через: return [object autorelease] и поэтому был создан внутри метода, который был позвонил сначала.

И еще один:

Например, если я сделаю следующее:

request = [[NSMutableURLRequest alloc] initWithURL: url];

Могу ли я после этого освободить URL-адрес, или он все еще должен застрять, чтобы запрос был действительным?

Ответы [ 4 ]

1 голос
/ 23 июля 2010

В вашем первом блоке кода вы никогда не изменяете значение строки myStr, возвращаемые значения из метода просто отбрасываются. Если вы измените строку так:

    NSString *myStr2 = [self modString1:[self modString2:myStr]];

Строка myStr2 будет иметь значение «Привет, как насчет этого? Мистер Память», и это будет автоматически выпущенный объект, который вам не нужно освобождать.

Кроме того, имейте в виду, что когда вы добавляете объект в изменяемый массив, объект автоматически сохраняется, так что вы можете освободить его после добавления в массив, и объект останется живым, пока объект не будет удален из массив или массив освобождается.

1 голос
/ 23 июля 2010

Если вам нужно только внутри вашего метода, вам не нужно его сохранять.Если вам нужно сохранить его в переменной экземпляра для последующего использования, сохраните его и отпустите в методе dealloc или при назначении нового объекта переменной экземпляра.

Примеры, относящиеся к моемукомментарий

Если вы измените значение строки (NSMutableString), вам не о чем беспокоиться.Вам просто нужно освободить его в методе, который создал строку.У вас могут возникнуть проблемы, если вы возвращаете указатель на другую строку и назначаете эту новую строку предыдущей.В таком случае вы больше не можете получить доступ к исходному указателю, и у вас есть утечка памяти, поскольку вы больше не можете ее освободить

Пример 1

{
    NSArray * arr = [ [ NSArray alloc ] initWithObject: @"Foo", @"Bar", nil ];
    [ self someMethod: arr ];
    [ arr release ];
}
- ( void )someMethod: NSArray * arr
{
    arr = [ NSArray emptyArray ];
}

Это нормально, утечки памяти нет, даже если вы назначите другой массив в someMethod, потому что указатель является локальным для метода и не повлияет на исходный указатель.

Пример 2

{
    NSArray * arr = [ [ NSArray alloc ] initWithObject: @"Foo", @"Bar", nil ];
    [ self someMethod: &arr ];
}
- ( void )someMethod: NSArray ** arr
{
    *( arr ) = [ NSArray emptyArray ];
}

Здесь мы имеем утечку памяти, поскольку мы изменяем исходный указатель.Обратите внимание, что мы использовали **, что означает, что у нас есть указатель на указатель.

Пример 3

{
    NSArray * arr = [ [ NSArray alloc ] initWithObject: @"Foo", @"Bar", nil ];
    arr           = [ self someMethod: arr ];
}
- ( NSArray * )someMethod: NSArray * arr
{
    return [ NSArray emptyArray ];
}

Утечка памяти, поскольку мы переопределили указатель наarr массив.Он был выделен, но мы не можем его освободить, так как указатель указывает на другую переменную.

0 голосов
/ 23 июля 2010

Еще один фрагмент кода: мне все еще не по себе:

Предполагается, что это часть функции.

NSArray *txtArray = [[NSArray alloc]init];</p> <p>if(aTxtField.text != NULL){ NSString *aTxtFieldTxt = [[NSString alloc]initWithString:aTxtField.text]; aTxtFieldTxt = [aTxtFieldTxt stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];</p> <p>[aTxt appendString:waotwTxtFieldTxt]; [aTxtFieldTxt release];</p> <p>txtArray = [aTxt componentsSeparatedByString:@" "]; aTxt = [[txtArray objectAtIndex:0] mutableCopy];</p> <p>for(int i = 1; i < [txtArray count]; i++){<br> [aTxt appendString:@"+"]; [aTxt appendString:[[txtArray objectAtIndex:i]copy]]; }</p> <p>[txtArray release]; return aTxt; }</p> <p>

Это было бы хорошо?

0 голосов
/ 23 июля 2010

Я собираюсь попытаться объяснить указатели, извините, если вы уже знаете это.

Большинство объектов objc являются указателями. Вы можете сказать, потому что у них есть * в конце имени объекта. NSString не является указателем, но NSString * является указателем.

Объект указателя NSString (NSString *) содержит только адрес пространства в памяти, где хранится эта строка. Когда вы создаете объект-указатель, вам нужно спросить у компьютера место для хранения вашего объекта. В objc вы делаете это, вызывая статический метод alloc. Так

NSString* s = nil; //s contains NOTHING
s = [[NSString alloc] stringWithString:@"hello"]; //space in memory is created for s, s contains the address to that memory. That memory block now holds "hello".

Теперь ваш компьютер хочет, чтобы вы сказали, если вы больше не будете использовать этот блок памяти. Это когда вы звоните

[s release];

, чтобы ваш компьютер знал, что он может захватить этот блок памяти (я полагаю, вы знаете об управлении памятью в противоположном стиле, с которым работает objc). Если вы попытаетесь получить доступ к этому блоку памяти ПОСЛЕ того, как он перестанет быть вашим, тогда вы получите все эти забавные ошибки памяти.

Теперь, когда вы вызываете метод, который требует от вас передать объект, такой как

[foo doSomethingWith:s];

То, что вы на самом деле передаете, это не объект "привет", вы передаете указатель на адрес в памяти, который содержит "привет". Такой способ работы очень удобен, когда у вас ОГРОМНАЯ структура данных (например, массив размером в 1 000 000). Вместо того, чтобы передавать огромный массив в функцию, вы просто передаете указатель этого массива. Это быстрее и эффективнее.

Так, когда вы должны освободить выделенные объекты? Обычно вы хотите освободить их , когда они вам больше не нужны , но в той же функции, в которой вы их разместили. Если они являются переменными экземпляра, вы размещаете их в функции init вашего класса, а освобождаете в функции dealloc. Во многих случаях вам не нужно сохранять / копировать вещи , поэтому, если у вас нет ошибок памяти, я бы не стал беспокоиться об этом.

Надеюсь, это поможет XD. Если какая-либо информация не является точной для objc, извините. Я изучил управление памятью на C ++, и оно совершенно другое.

...