简体   繁体   English

iPhone,将对象传递给方法,内存管理

[英]iPhone, passing object to method(s), memory management

I know there are a lot of questions on this topic already, but it is just not clear to me yet. 我知道已经有很多关于此主题的问题,但是对我来说还不清楚。 So, what I am still wondering about is, if I call a method and pass it an object, do I then have to retain this object inside my method to use it there. 所以,我仍然想知道的是,如果我调用一个方法并将其传递给一个对象,那么我是否必须将该对象保留在我的方法中才能在其中使用它。 And if I retain it, where do I release it. 如果我保留它,该在哪里释放它。 Lets make a bit of a more complex example. 让我们举一个更复杂的例子。 Could someone explain whats wrong with this: 有人可以解释这是怎么回事:

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];
}

This is so confusing to me. 这让我感到困惑。 Lets assume I create an object inside a method: 假设我在方法内部创建一个对象:

[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;
}

Would this be correct? 这是正确的吗? Another thing: If I copy a string from an array into a string like: 另一件事:如果我将数组中的字符串复制到类似以下的字符串中:

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

does the retain the whole array, or whats happening here? 保留整个数组,还是这里发生了什么? Would that mean I have to release the array? 那是否意味着我必须释放阵列? I dont get it. 我不懂。 Are there any practical resources apart from apple`s? 除了苹果之外,还有其他实用资源吗? I really want to understand this... 我真的很想了解这个...

A method does not own an object which is getting passed to it as an argument?! 方法不拥有作为参数传递给它的对象? Right? 对? And I only would have to retain an object in a method, if the object itself is an object returned by a method (which was called before) with an autorelease via: return [object autorelease] and therefore was created within the method, which was called at first. 而且,如果对象本身是通过以下方法自动释放的方法(之前称为)所返回的对象,则该对象本身就是方法中的对象:return [object autorelease],因此是在方法内部创建的,即首先打电话。

And another one: 还有一个:

For example if I do the following: 例如,如果我执行以下操作:

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

can I then release the url after this, or does it still have to stick arround for the request to be valid? 我可以在此之后释放该URL,还是仍然必须保留该网址才能使请求有效?

If you only need it inside your method, you don't need to retain it. 如果只在方法内部需要它,则不需要保留它。
If you need to store it in an instance variable for use later, the retain it, and release it in the dealloc method, or when you assign a new object to the instance variable. 如果需要将其存储在实例变量中以备后用,请保留它,并在dealloc方法中释放它,或者在为实例变量分配新对象时将其释放。

Examples concerning my comment 有关我的评论的示例

If you modify the value of the string (NSMutableString), you don't have to worry. 如果您修改字符串(NSMutableString)的值,则不必担心。 You just need to release it in the method which created the string. 您只需要在创建字符串的方法中将其释放。 You may have problems if you return a pointer to another string, and if you assign this new string to the previous one. 如果您返回指向另一个字符串的指针,并且将此新字符串分配给前一个字符串,则可能会遇到问题。 In such a case, you can't access the original pointer anymore, and you have a memory leak as you can't release it anymore 在这种情况下,您将无法再访问原始指针,并且由于无法释放而导致内存泄漏

Example 1 例1

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

This is ok, no memory leak, even if you assign another array in someMethod , because the pointer is local to the method, and it won't affect the original pointer. 没关系,即使您在someMethod分配了另一个数组,也不会发生内存泄漏,因为指针是该方法的局部指针,并且不会影响原始指针。

Example 2 例2

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

Here, we have a memory leak, as we modify the original pointer. 在这里,我们在修改原始指针时发生了内存泄漏。 Note we used **, meaning we have a pointer to a pointer. 注意我们使用了**,这意味着我们有一个指向指针的指针。

Example 3 例3

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

Memory leak, as we've redefined the pointer to the arr array. 内存泄漏,因为我们已经重新定义了指向arr数组的指针。 It has been allocated, but we can't release it since the pointer points to another variable. 它已被分配,但由于指针指向另一个变量,所以我们无法释放它。

In your first block of code, you are never really modifying the value of the string myStr, the returned values from the method is just tossed out. 在您的第一段代码中,您永远不会真正修改字符串myStr的值,只是将方法返回的值扔掉了。 If you modify the line to read like this: 如果将行修改为如下所示:

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

The string myStr2 will have the value of "Hello How about this? Mr. Memory", and it will be an autoreleased object, which you do not have to release. 字符串myStr2的值为“你好,这是什么?先生。内存”,它将是一个自动释放的对象,您不必释放它。

Also, keep in mind that when you add an object to a mutable array, the object is automatically retained, so that you can release it after adding it to the array, and the object will stay alive until the object is removed from the array or the array is released. 另外,请记住,将对象添加到可变数组时,该对象会自动保留,以便在将其添加到数组后可以释放它,并且该对象将保持活动状态,直到从数组中删除该对象为止。阵列被释放。

I'm going to try and explain pointers, sorry if you already know this. 我将尝试解释指针,如果您已经知道这一点,对不起。

Most objc objects are pointers. 大多数objc对象都是指针。 You can tell because they they have a * at the end of the object name. 您可以知道,因为它们在对象名称的末尾带有*。 NSString is not a pointer, but NSString* is a pointer. NSString不是指针,但是NSString *是指针。

An NSString pointer (NSString*) object contains only the address to a space in memory where that string is stored. NSString指针(NSString *)对象仅包含该字符串存储在内存中的空间的地址。 When you create a pointer object you need to ask the computer for space to store your object. 创建指针对象时,需要向计算机询问用于存储对象的空间。 In objc you do this by calling the static alloc method. 在objc中,您可以通过调用静态alloc方法来做到这一点。 So 所以

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".

Now, your computer wants you to tell it if you won't use that memory block anymore. 现在,您的计算机希望您告诉它是否不再使用该内存块。 That is when you call 那是你打电话的时候

[s release];

to let your computer know that it can take over that memory block (I assume you know about the counter-style memory management that objc works with). 让您的计算机知道它可以接管该内存块(我想您知道objc可以使用的计数器样式的内存管理)。 If you try to access that memory block AFTER it's no longer yours, then thats when you get all those fun memory errors. 如果您尝试访问该存储块之后不再是您的存储块,那么当您遇到所有这些有趣的存储错误时,就可以了。

Now when you call a method that requires you to pass an object like 现在,当您调用需要传递诸如以下内容的对象的方法时

[foo doSomethingWith:s];

What you're actually passing isn't the object "hello", you're passing the pointer to the address in memory that holds "hello". 您实际传递的不是对象“ hello”,而是将指针传递到保存“ hello”的内存中的地址。 This way of doing things comes in handy when you have a HUGE data structure (like an array of ints of size 1,000,000). 当您具有庞大的数据结构(例如大小为1,000,000的整数数组)时,这种处理方式会派上用场。 Instead of passing the huge array into a function, you just pass the pointer of that array. 无需将庞大的数组传递给函数,只需传递该数组的指针即可。 This is faster and more efficient. 这样更快,更高效。

So when should you release allocated objects? 那么什么时候应该释放分配的对象呢? You usually want to release them when you no longer need them , but in the same function in which you allocated them. 通常, 当您不再需要它们时 ,而是在分配它们的相同功能中,就希望释放它们。 If they are instance variables then you allocate in the init function of your class and release in the dealloc function. 如果它们是实例变量,则可以在类的init函数中进行分配,并在dealloc函数中进行释放。 In many cases you don't need to retain / copy things , so unless you're having memory errors I wouldn't worry about those. 在许多情况下,您不需要保留/复制内容 ,因此,除非您遇到内存错误,否则我不会担心。

I hope this helps XD If any of the info isn't accurate for objc, I'm sorry. 希望这对XD有帮助。如果objc的信息不正确,对不起。 I learned memory management with C++ and it's totally different. 我通过C ++学习了内存管理,这是完全不同的。

Another piece of code: I am still not comfortable with it: 另一段代码:我仍然对它不满意:

Assuming this is part of a function. 假设这是功能的一部分。

NSArray *txtArray = [[NSArray alloc]init];

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

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

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

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

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

Would this be allright? 这样可以吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM