views:

1220

answers:

3

I'm working with AsyncSocket where the the AsyncSocket object calls a delegate method below whenever it receives data from remote end:

- (void)onSocket:(AsyncSocket*)socket didReadData:(NSData*)data withTag:(long)tag;

Now, within this method, I pass the NSData object into the following command to get a NSString representation of the data received:

NSString *body = [NSString stringWithCString:[data bytes] length:[data length];

Does NSString stringWithCString: length: retain the byte array I pass in? Do I need to retain the NSData *data? Do I need to be releasing NSString *body at the end?

Thanks. I want to get memory management right in terms of delegates methods...

A: 

You don't have to retain the NSData array since its content will be converted/copied into the new NSString object.

The NSString object returned has a retain count of 1 but it has been added to the autorelease pool.
This means that it will be automatically released once the autorelease pool gets destroyed. In case you are using the default autorelease pool created by AppKit this will occur at the end of the current event loop handling. So if you use this string object only in that method "onsocket:..." you are fine.

If you want to keep the NSString object after leaving the method you should retain it or instantiate it by allocating and initializing it like this:
[[NSString alloc] initWithBytes:[...] length:[...] encoding:[...]]
This NSString object will also have a retain count of 1 but you have to explicitly release it when you no longer need it.

Btw. [NSString stringWithCString:length:] is deprecated since OSX 10.4

Volker Voecking
A: 

Pholker is correct; you should be using stringWithCString:encoding: instead.

Retain/Release is only needed for objects; as you are passing in a C-string (which is not an object, unlike NSString) there is nothing to retain or release.

As you are using a convenience constructor the NSString has a retain count of 1 but is added to the autorelease pool, so at some time after you leave the code block, this will be released. You don't need to explicitly use the alloc and init methods to be able to retain it. I mean, it is created with a retain count of 1 (but will be autoreleased) If you call retain on it, that will increment the count to 2, but at some time later, it will be autorelased, and the retain count will drop to 1.

If you don't call init, retain, copy or mutableCopy on an object, you can assume it will be autoreleased and you don't need to explicitly release anything. But if you want to hold onto an object outside of a code block, you need to call retain and then release it some time later (usually in the dealloc method of the class in which the object was created).

Abizern
+2  A: 

Does NSString stringWithCString: length: retain the byte array I pass in?

It's not possible to retain a byte array. Only objects can be retained.

Do I need to retain the NSData *data?

No. Because there's no way for the string to retain the data (which it doesn't know about) or its contents, the string will copy the bytes. (Think about what you would do if you were implementing this method: This is it.)

Let's change cases and look at what you would do if you were passing the data object in, instead of the bytes.

If the string does retain the data, then you don't need to worry about the data dying out from under the string, because the string is retaining it. If it doesn't retain it, the string either made its own copy or isn't holding on your data at all.

So other objects' retentions don't matter. Don't worry about them. Worry only about who owns what, and retain or not accordingly.

Do I need to be releasing NSString *body at the end?

Well, you didn't retain it, you didn't alloc it, and you didn't copy it. Therefore, you don't own it. So, no.

If you do want to take ownership of the object, you'd retain it or make (and then own) your own copy. Then you would release it.

Peter Hosey