Returning autoreleased objects using ARC - objective-c

Assuming that I wrote the code below in a class A:
-(NSArray *) returnListNames {
NSArray *returnList = [NSArray arrayWithArray:myListNames];
return (returnList);
}
And in a class B I get that list in some scope in this way:
{
/* Without ARC I would retain the array returned from ClassA
to guarantee its reference like this:
[[myClassA returnListNames] retain]; */
NSArray *myNames = [myClassA returnListNames];
}
Considering that the returnList was allocated using an autorelease method, how can I guarantee that I won't lose the reference to it using ARC (under which I can't use retain)?
Will I have to use [[NSArray alloc] init] on the myNames array? Or I must use alloc on returnList instead of an autorelease method? Or can I just rely on ARC? Or is there another solution?

ARC will handle this for you, so you can just rely on it and go about your business with that array. If it sees that you need to retain myNames, it will add a retain call for you for example, or do whatever else it actually does when you compile the code that uses it.

Related

Keep a class-level array of instantiated objects without having to explicitly remove them

I have a class, let's say Chicken, and I want a class-level method to enumerate all the currently existing Chickens. To do this, I keep a class-level NSMutableArray and add self to this in the init method.
This is great and my enumeration method simply returns a (non-mutable) pointer to this array.
The problem is that I can no longer deallocate a chicken by removing all pointers to it, as there is always a strong pointer left in the array.
E.g. If I do this...
Chicken *chick = [[Chicken alloc] init];
// Do something with the chick
chick = nil;
The chicken lives on because there is a strong pointer to it in the array. I could have a -[Chicken kill] method, which removes it from the array, but that's not neat.
What's the neatest way around this?
You can use [NSHashTable weakObjectsHashTable] to store objects. It is basically an array holds weak references. It is safe, and clean.
If NSHashTable is not available, or suitable (you want to hold key-value pair like NSDictionary) but you have ARC with __weak supported, you can use a wrapper object to hold weak reference.
I use block to hold weak ref in this example
NSMutableDictionary *globalDict = [NSMutableDictionary dictionary];
// put object
id obj = [Foo new];
__weak id weakRef = obj;
globalDict[key] = [^() { return weakRef; } copy];
// read object
id (^block)(void) = globalDict[key];
id obj = block ? block() : nil;
if (!obj) {
[globalDict removeObjectForKey:key];
}
Use + (NSValue *)valueWithNonretainedObject:(id)anObject values inside your array. To simplify your API, you can create a wrapping method of +arrayOfAllChickens which would iterate all non-retained values and add them to an array and return that.
Remember to remove the values from the array in dealloc or you could hit a bad access crash.

NSString Release

I have this code of string and I have problems trying to free up memory, I have understood that only those who release it initializes and is not autorelease but I had problems with the string "end", and as nSum release.
NSString *urlBase = [[NSString alloc] initWithFormat:#"http://service.svc/"];
NSString *op = [[NSString alloc] initWithFormat:#"op1"];
NSString * final = [urlBase stringByAppendingFormat:op];
NSString * nSum = sumTextfield.text;
final = [final stringByAppendingFormat:nSum];
//release
[ urlBase release ];
[ op release ];
//[final release]; error
//[final autorelease]; error
thank for you help.
UPDATE:
- (IBAction)mostrarOpciones {
// code (UP)
}
If you create an object using a method that begins with init, new, copy, or mutableCopy, then you own that object and are responsible for releasing it (or autoreleasing it) when you're done with it. If you create an object using any other method, that object is autoreleased, and you don't need to release it. In that case, you actually need to retain the object if you want to keep it around. Apple has a Memory Management Programming Guide that includes all these rules.
The code you've posted is actually correct. You need to release urlBase and op because you created them using a method beginning with init (initWithFormat: in this case). final and nSum are already autoreleased for you. final was created by a method that doesn't begin with init, new, copy or mutableCopy (in this case, the factory method stringByAppendingFormat:). nSum was returned by a method called text, and you can assume that sumTextField "owns" it or has autoreleased it before returning it to you, and so you're not responsible for releasing it.
you cannot release NSString which you did not allocate. Since your two variables are not allocated, they need not to be released.

Can I reuse my pointer after it's been added to a mutable array?

Let's say I've got an array with strings.
NSArray *names = [NSArray arrayWithObjects: #"One", #"Two", #"Three", nil];
What I want is to initiate objects of some custom class and them add them to a mutable array. I'm using a custom init method that takes a string argument.
To be more specific, I want to [SomeClass alloc] initWithName: aName] and add the resulting object to a NSMutableArray.
I'm thinking of using Objective-C fast enumeration. So what I get is:
NSMutableArray *objects = [NSMutableArray arrayWithCapacity: [names count];
for (NSString *name in names) {
[objects addObject: [[[SomeClass alloc] initWithName: name] autorelease]];
}
The problem is that I can't add nil to the array and I don't like exception handling. However, my initiation method may return nil. So I decide to check first before adding (prevention). My new for-in-loop is:
SomeClass *someObject;
for (NSString *name in names) {
someObject = [[[SomeClass alloc] initWithName: name] autorelease];
if (someObject) {
[objects addObject: someObject];
}
}
Now, instead of immediately passing the new object to the array, I'm setting up a pointer someObject first and then passing the pointer to the array instead.
This example raises a question to me. When I someObject = [[[SomeClass alloc] initWithName: name] autorelease] in the loop, do the existing objects (which are added using the same pointer) in the array change too?
To put it in other words: does the addObject: (id)someObject method make a new internal copy of the pointer I pass or do I have to create a copy of the pointer — I don't know how — and pass the copy myself?
Thanks a lot! :-)
It's fine to reuse someObject; if you think about it, you're already reusing name each time you go through the loop.
-addObject: may or may not copy the object that you pass in. (It doesn't -- it retains the object rather than copying it, but it's conceivable that some NSMutableArray subclass could copy instead.) The important thing is that this code really shouldn't care about what -addObject: does.
Also, don't lose sight of the distinction between a pointer and the object that it points to. Pointers are just references, and a pointer is copied each time you pass it into a method or function. (Like C, Objective-C passes parameters by value, so passing a pointer into a method results in putting the value of the pointer on the stack.) The object itself isn't copied, however.
Short answer: no, you don't have to worry about reusing someObject.
Slightly longer answer: the assignment—someObject = ... assigns a new pointer value to the someObject variable; addObject: is then getting that value, not the address of someObject itself.
I think you're getting confused in the concept of pointer here. When you say someObject = [[[SomeClass alloc] init... you are basically pointing the someObject pointer to a new object. So to answer your question- your current code is fine.
As for whether arrays maintain copies of the objects added to them - NO, the array retains the object you add to it. However, that doesn't matter to your code above.
Three20 provides the answer!

Objective C Memory Management Woes

I know this has been discussed ad-nauseum but I just don't get some of the memory management. I understand that retain keeps the object alive and copy gives one a separate copy of an object.
What I don't get is when it comes to ivars & properties, retain as a property means that the setter releases the old value & retains the new:
property = newValue;
// retain
if (property != newValue)
{
[property release];
property = [newValue retain];
}
but I've seen examples where they assign static strings to the retain property ivars e.g.
self.stringProperty = #"something";
(some other code)
self.stringProperty = #"somethingElse";
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
Also, if an object is declared with the retain property & then is assigned something with init, e.g.
#property(retain)someArray;
someArray = [[NSArray alloc] initWithArray:arbArray];
does that mean someArray now has a retain count of 2 but if it was created with
someArray = [NSArray arrayWithArray:arbArray];
the retain count is only 1 because the 2nd is a factory method?
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
You can pass release to a constant string, it just won't do anything meaningful, so those lines of code are valid.
does that mean someArray now has a retain count of 2 but if it was created with...the retain count is only 1 because the 2nd is a factory method?
Well, first of all,
someArray = [[NSArray alloc] initWithArray:arbArray];
doesn't use the methods created by #property, it just accesses the ivar directly. To use the property methods, you'd have to use self.someArray = ...;.
But yes,
[[NSArray alloc] initWithArray:arbArray]
returns an object with an effective retain count of 1, and
[NSArray arrayWithArray:arbArray]
returns an object with an effective retain count of 0, so if you did pass them through the "retain" setter created by #property, the ivar would have an effective retain count of 2 and 1, respectively.
This is more that one question, but anyway...
Static strings are special cases in a number of ways, one of which is that you can retain and release them to your heart's content without it having any effect.
As an aside, NString properties often have copy rather than retain semantics, which would anyway obviate that question if it mattered. But it doesn't.
In your second case, assigning to a retain property directly from an alloc (or copy or other ownership-granting call) is bad practice and will leak unless you actively add a corresponding release afterwards, or autorelease during, eg:
self.someArray = [[[NSArray alloc] initWithArray:arbArray] autorelease];
But there's really no reason not to use the class method in this particular case.
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
It's not a static string, it's a constant string. However, that is irrelevant to the question, but actually you are allowed to send -retain to any Objective-C object derived from NSObject except NSAutoreleasePool. If you look at the retainCount (a bit naughty, but since we are discussing implementation, OK) of a constant NSString e.g.
NSLog(#"retain count = %u", [#"foo" retainCount]);
you'll most likely find it's set to a really big number (UINT_MAX in fact). This is a signal to the run time to ignore calls to release and retain.
By the way, forgetting to release objects won't crash the program straight away. In fact, if you have lots of RAM, you might not notice until the OS starts swapping.
does that mean someArray now has a retain count of 2 but if it was created with
No, because you didn't use the property to assign the new array, you went straight to the ivar:
self.someArray = [[NSArray alloc] initWithArray:arbArray];
would be a leak.
self.someArray = [NSArray arrayWithArray:arbArray];
would be OK.

Balance retain with release?

I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
gary
No, but you shouldn't need to do this at all since you are not allocating anything. You could simply return name and that should be fine. Was there a reason you needed to add this retain/autorelease?
A little more explanation, what is happening here is that your retain count goes up by one when you do a retain, and then down by 1 when the scope exists because of the autorelease.
I don't know how your variable definition is in your class but the rule is that in your getter you should return the object unchanged for the reference count. It's the responsability of the caller to call retain if it want to keep a reference on it.
- (NSString*) name {
return name;
}
// caller
NSString* name = object.name;
[name retain]; // if necessary. If the string is used only in the context of a method you do not have to retain it.
If you are using the returned value as a field in another class you should define your field like this:
#property(retain, nonatomic) NSString* name;
With this a retain will be called when you assign to the variable.
No, this is fine. autorelease will cause the value to be released when the current autorelease pool is drained.
Every retain must be matched with exactly 1 of either release or autorelease.
However, I believe both the retain and autorelease are unneeded here. Generally you want to use that autorelease idiom because you've alloc'ed something in the method.
No. The autorelease will balance it out. I don't think, however, that the retain and autorelease would be necessary. You can simply use return name.
As others have said, you do not need to retain or autorelease the property. Since callers of the 'getter' method did not create the object, they do not own it, and you are safe to assume that they won't tinker around with its retain count.
But, callers could potentially change the value of the variable returned by the getter, which would affect the object. Therefore, it would probably be a better idea to return a copy of your variable, especially since it is an NSString. (Getters for NSString objects often return a copy.)
- (NSString *)name {
return [[name copy] autorelease];
}
In this scenario, you are creating a copy of the variable, so you 'own' it. By autoreleasing it before it is returned, you ensure that it will survive long enough to be used in the caller's scope, and that any changes they make to the 'name' variable will not affect the underlying object.
I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
No, because you are already releasing it. autorelease just means “send yourself release later”.
I think you should review the memory-management rules.
I think I might have figured it out:
if [myString] is created outside the method then your safe to use ...
return myString;
if on the other hand [myString] is created inside the method and therefore needs to be released and returned, then you use.
myString = [[NSString alloc] initWithFormat: #"Send me home"];
return [myString autorelease];
This way the method sets [myString] to autorelease, Basically the object is created, set to autorelease and returned. The object will ultimately be released when the pool is destroyed.