ARC and releasing memory - iphone

I have read many articles online, and I am a bit confused about ARC. I will list my questions below, please help me answer them.
1.) What does the keyword strong do (in #property (nonatomic, strong) …)?
2.) Don't we have to release or autorelease what we alloc anymore, because I get a warning saying that I need not have to. (I am not at my Mac, so I can't copy the warning I got.)
3.) I couldn't find the Leaks tool in Xcode 4.2. Where did it go? Or don't we have to check for leaks anymore?
4.) When creating the project using Xcode 4.2, I clicked on "enable ARC", so will my program work on iOS 3? (I think ARC only supports iOS 4 and above.)

strong is an ARC analog to retain (there's no retain under ARC). It means that property value will be hold by class where the #property was defined, and released upon reassignment or dealloc. (Note that under ARC there's no need to release or nullify properties in dealloc).
The point of ARC is taking care of retain/release routine by compiler, so there's no need for manual memory management methods.
You can check for leaks by running Profile (Product -> Profile menu) and selecting Leaks instrument. Leaks can be introduced with cyclic references or in CoreFoundation code (ARC doesn't work with CoreFoundation). Also if you are mixing ARC and non-ARC code, the latter could be a source of leaks.
ARC is supported by OS starting from iOS 4.0 (though iOS 5 SDK is needed). The key difference between 4.0 and 5.0 ARC support is availability of weak property specifier. Weak property (__weak variable) will be automatically nullified when the strong value it refers to is released. There are no weak properties in 4.0, so __unsafe_unretained specifier should be used (It's a close analog to assign specifier, it doesn't retain value and can point to already deallocated value, so it's dangerous).
Here's a great explanation of ARC:
Everything you need to know about automatic reference counting

Strong is equivalent to retain in ARC. It indicates ownership: What does the "strong" keyword do
No, that's done for you. ARC inserts those statements in (compiled) code automatically. That's its main job. But, per Abizern's comment, this only works for your objects and Cocoa objects. If you're using Core Foundation (CF*) classes then you must read about the __bridge family of casts. You might start reading here.
It's in Instruments. Per iHunter's answer, Cmd+I or Product->Profile, then choose Leaks. Particularly important given (2).
It will not work.

Well, there are already three answers that cover the main things so I'll focus on a single detail here, that isn't already mentioned:
3.) I couldn't find the Leaks tool in Xcode 4.2. Where did it go? Or don't we have to check for leaks anymore?
Yes we do still need to check for leaks:
ARC is not garbage collection, it is automated retain/release.
Thus, it is still possible — in fact, it's pretty easy — to create leaks!
Consider the following example:
#class Puppet;
#protocol PuppetDelegate : <NSObject>
- (void)puppetDidTwistStrings:(Puppet *)puppet;
#end
#interface Puppet : NSObject {
id <PuppetDelegate> delegate_;
}
- (id)initWithPuppetDelegate:(id <PuppetDelegate>)delegate;
- (void)unravelStrings;
#end
#implementation Puppet
- (id)initWithPuppetDelegate:delegate
{
if (!(self = [super init])) return nil;
delegate_ = delegate;
return self;
}
// assume some implementation for unravel strings
#end
#interface MasterOfPuppets : NSObject <PuppetDelegate> {
NSMutableArray *puppets_;
}
- (void)puppetDidTwistStrings:(Puppet *)puppet;
- (void)bringOutAPuppet;
#end
#implementation
- (id)init
{
if (!(self = [super init])) return nil;
puppets_ = [[NSMutableArray alloc] init];
return self;
}
- (void)bringOutAPuppet
{
Puppet *newPuppet = [[Puppet alloc] initWithPuppetDelegate:self];
[puppets_ addObject:newPuppet];
}
- (void)puppetDidTwistStrings:(Puppet *)puppet
{
BOOL isOurPuppet = [puppets_ containsObject:puppet];
if (!isOurPuppet) return;
[puppet unravelStrings];
}
#end
This example is (admittedly) a little stupid, but this code will leak, and ARC is not going to help you about it, whereas garbage collection would:
A MasterOfPuppets can have many puppets, which he stores in an instance variable — so far so good.
A Puppet has a delegate which it is going to inform if its strings are entangled — and here it starts.
Whereas in non-ARC code an instance variable was simply a pointer that was being assigned to, ARC assumes that if you stash something in a variable, you want to cling on to it and it will retain the value unless you tell it not to.
So you have a classical retain-cycle here and ARC won't save you from those.
This may seem a contrived and far-fetched example, but it's not: I've seen this quite a bit in delegate relationships.
(The solution, by the way, is pretty simple: declare Puppet's delegate_ instance variable as weak and everything works as it should.)

Related

Objective C ARC equivalent for self?

What is the equivalent keyword i can use in the place of self in ARC enabled projects?
ex:- [self mymethod]; what is ARC equivalent of this method call?
I don't quite get it? Why ARC should have different syntax for method calls? It is an automatic memory management, where in most cases you won't need to use retain/release, nothing more. So it would look like this:
[self mymethod];
In ARC(Automatic Reference Counting),you don't need to release or retain. It has nothing to do with calling methods!
ARC - Automatic Reference Counting implements automatic memory management for Objective-C objects and blocks, freeing the programmer from the need explicitly insert retains and releases. Since this is handled at compile time, no collector process is need to continually clear memory and remove unreferenced objects.
For calling a method, you still do it this way:[self mymethod];
it's still the same
[self myMethod];
But in ARC environment, IIRC, you need to do it like this: (I don't know if this is the source of your question, but when I migrated the first time to ARC, I get compile error if I'm not doing this).
#interface myController()
- (void)myMethod; // you need to declare the method here, if you haven't declared it on the .h
#end
#implementation
- (void)viewDidLoad
{
[super viewDidLoad];
[self myMethod];
}
- (void)myMethod
{
NSLog(#"!");
}
#end
hope this help

confused by ARC

The codes below I used on Xcode 3.2 and worked very well
#interface MoObject : UIViewController
{
NSMutableArray *categoryArray;
}
#property (nonatomic, retain) NSMutableArray *categoryArray;
#end;
#implementation MyObject
#synthesize categoryArray;
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *a = [[NSMutableArray alloc] init];
categoryArray = a;
[a release]; //AAA:I can not release this, it does not report compiling error , but after some operation, it will cause exec bad error
}
- (void)dealloc {
[category release];
[super dealloc];
}
I just move to Xcode 4.3.1 iOS 5.1
the same function causes so many exec bad error.
Even I close the ARC of whole project.
The problem still exist, it looks like I can not release the object array at point AAA
Welcome any comment
The point of ARC is that it handles the retain/release code for you. Since your array "a" is declared locally, when that function ends, ARC will insert the code release it for you. Same for dealloc - you don't need it with ARC (and actually can't use it).
But if you don't like or want to learn ARC you don't have to use it. It's an option when you create a new project.
You are not using ARC. If you were, code using -release would not even compile. Neither would calling [super dealloc] in your -dealloc method.
What you have is just an ordinary memory management bug. You are assigning a directly to the instance variable categoryArray. You are not using the setter which is synthesized for the property and it is the setter which does the proper memory management. Therefor, categoryArray ends up pointing to a deallocated object. If you were to use either self.categoryArray = a or [self setCategoryArray:a], which are equivalent statements, then your bug would go away.
Under ARC, this bug would be mostly hidden. The categoryArray instance variable would by default be __strong, so the array would be retained at least as long as categoryArray pointed to it and you wouldn't get EXC_BAD_ACCESS errors. However, it's still buggy to directly assign to it, bypassing the setter, except within initializer methods.

iphone - properties and instance variables

Suppose I have this code...
foo.h
#interface Foo : NSObject {
NSString *aString; // 1
}
#property (nonatomic, retain) NSString *aString;
foo.m
#synthesize aString = _aString;
....
- (void)dealloc {
[aString release];
[super dealloc];
}
My questions are:
do I really need to declare aString in "1"? (see code)
if I am synthesizing aString = _aString, I am already creating an instance
variable, right?
if I am retaining the property on foo.h (#property), why Xcode complains if I release aString in dealloc?
thanks.
You are mixing up the property and the backing variable. "aString" is the property, which you access via method call (e.g. [self aString]). "_aString" is the backing variable, which you access directly (e.g. _aString).
Taking your questions in order:
No. This is an unused variable because you told the compiler to use _aString as the variable. (You don't actually need to declare either one in the modern run-time.)
Yes, as indicated in my answer to the first question.
Because the compiler expects you to send a message to an object, and "aString" is undefined as written. Normally you would use [self aString] to access the object, but this is a special case: in -dealloc and in -initXYZ you don't use accessor methods because of potential side effects. Switch to [_aString release] and everything will work (unless you have ARC, in which case you don't release at all.
With your #synthesize, the instance variable (your "1") should be NSString* _aString.
The reason you use synthesize with a differently named variable is so that you always use self.aString to properly release the old object instead of accidentally overwriting the pointer by directly modifying aString.
Do you have ARC enabled? If so, that's why Xcode complains about releasing it.
To answer your questions in order:
No. There might some sort of "best-practice" reason that I'm missing, but #property will synthesize the instance variable as well.
When you declare aString = _aString, what that allows you to do is directly manipulate _aString without accessing the synthesized getter/setter (by calling _aString) or use the synthesized getter/setters (by calling self.aString).
You are likely releasing it somewhere else, someone else is over-releasing it, or you're using ARC. With NSStrings (and other simple objects that have deep copy method readily available), I find it best to use #property (copy), and _aString = [stringPassedToInit copy], so that you are the only one handling your string's retain count. If you're using ARC, you don't need to worry about retain/release in most instances.
No, you don't need to declare ivars any more (since iOS 3 I think). You can delete the entire { ... } part of your interface declaration and it won't make any difference.
It's complaining because your ivar is named _aString, not aString. You need to say
[_aString release]
instead.
Answers : -
do I really need to declare aString in "1"? (see code) - Now with iOS 4 onwards you won't need to declare.
if I am synthesizing aString = _aString, I am already creating an instance variable, right? - Yes
if I am retaining the property on foo.h (#property), why Xcode complains if I release aString in dealloc? - now you need to use this - self.aString = nil, this will take care.
My answers are:
NO
YES
Try [_string release] instead.

Memory Management on the iPhone

I'm sorry to ask such a simple question, but it's a specific question I've not been able to find an answer for.
I'm not a native objective-c programmer, so I apologise if I use any C# terms!
If I define an object in test.h
#interface test : something {
NSString *_testString;
}
Then initialise it in test.m
-(id)init {
_testString = [[NSString alloc] initWithString:#"hello"];
}
Then I understand that I would release it in dealloc, as every init should have a release
-(void)dealloc {
[_testString release];
}
However, what I need clarification on is what happens if in init, I use one of the shortcut methods for object creation, do I still release it in dealloc? Doesn't this break the "one release for one init" rule? e.g.
-(id)init {
_testString = [NSString stringWithString:#"hello"];
}
There is a neat acronym to remember what you have to release
N.A.R.C - new, alloc, retain, copy.
If it's not created with alloc, new, copy, mutableCopy then you're not responsible for releasing it.
This site has some good quick overviews of things like memory management.
Here's a quote from cocoadevcentral:
If you create an object using the
manual alloc style, you need to
release the object later. You should
not manually release an autoreleased
object because your application will
crash if you do.
Just to clarify things a bit. When you get an object through N.A.R.C. as sylvanaar says you do need to release it. In other cases you are getting an autoreleased object that will be released automatically at some later time. That will be bad in the code you presented here, because you do want this string to stay around at least as long as your object. So you actually need to do an explicit retain to keep it alive for your object.
That is not directly answering your question, but rather anticipating the next one ;-)
If you set an attribute with an autorelease, the object in the attribute can die at anytime beyond the immediate scope. Convenience methods i.e. ones that start with a type: string, array, dictionary etc, return autoreleased objects. You only use autoreleased objects when you don't care whether or not they survive beyond the present scope.
What you really need to do in this case is use accessors, either the synthesized or custom, to manage your retention automatically.
If you do:
#property(nonatomic, retain) NSString *_testString; // .h
#synthesize _testString; //.m
then in code use the reference form:
self._testString = [NSString stringWithString:#"hello"];
... then the only place you have to release _testString is in dealloc. The compiler will create synthesized accessors which will automatically manage the properties memory for you.
By the way, you should not use underscores for names. Apple reserves underscore names for itself so you can get a naming collision.
In the first part of the example you do indeed have to have a release for the string somewhere.
In the second part of the example because its an autoreleased you don't need to call the additional release in the dealloc method. This will actually cause a crash as you are attempting to send a message to something that no longer exists...
On the contrary, you need to retain the object you get from stringWithString:. As you correctly noted, you don't own that object and thus don't need to release it. But because you don't own it, it's free to disappear at any time, leaving you with a crash if you're lucky (and a very odd bug if you're not). So you need to retain the object, and then you do need to release it in dealloc.
All of this is explained very well in the memory management guide. I suggest you read it over a couple of times. It's not very long or difficult, and once you internalize it, you'll never have to wonder again.
The rule is if you create an object with new, alloc, copy or you retain it, you need to release it. Objects created in any other way must not be released.
So in your specific case, you would not need to release your string created with stringWithString.
By the way, I would recommend the Cocoa and Objective-C: Up and Running book for learning more about things like this. Great introduction if you are new to Cocoa programming.

Objective-C changes between OS 2.2.1 and OS 3?

When I tried compiling my app for OS 3 I encountered an the following error:
error: type of accessor does not match the type of property
The error was for a property I tried to access that is defined as follows:
NSMutableArray *myArray
#property (readonly,nonatomic) NSArray* myArray;
the property is #synthesized in the implementation file.
This worked just fine in OS 2.2.1 but doesn't is OS 3.0
Writing the getter method myself solved the problem.
Is anyone aware of changes to objective-c between OS 2.2.1 and 3.0?
Is there any documentation for these changes?
The API changes document doesn't appear to contain anything about this issue.
EDIT
the error occurs when you try to access the property e.g.
NSArray *anArray = myClass.myArray;
As I mentioned above I found a workaround for this: writing the getter method myself, however what I'm really after is some kind of documentation from apple explaining this change and any other changes that are not API related.
Thanks for your help
This is a compiler bug.
Though you didn't specify it completely, I expect your code looks like this:
#interface Foo : NSObject {
NSMutableArray *objects;
}
#property (readonly, copy) NSArray *objects;
#end
#implementation Foo
#synthesize objects;
#end
The compiler is, unfortunately, confused between the declaration of the objects property and the declaration of the objects instance variable. Remember that properties and instance variables are different things in Objective-C; a property can be backed by an instance variable, but it's really part of the public interface of a class.
You can work around this by changing your code to clearly separate the definition of the instance variable from the definition of the property, for example by prefixing the name of the instance variable:
#interface Foo : NSObject {
NSMutableArray *_objects;
}
#property (readonly, copy) NSArray *objects;
#end
#implementation Foo
#synthesize objects = _objects;
#end
This way the compiler doesn't get confused about the property versus the instance variable in expressions like self.objects (which it shouldn't anyway, but apparently does).
Just to head off the inevitable response: Apple does not reserve the underbar prefix for instance variables. It's reserved for methods. Regardless, if you dislike the underbar, feel free to use another prefix.
edit: Original answer removed after peer review found it lacking. Please read Chris Hanson's comments on the matter. I'm leaving the rest here because I think it is still valid.
Note that even if you declare the property type to be NSArray, the object returned is still an NSMutableArray, and the mutable methods are defined for it. Declaring the property in this way does not prevent someone from accidentally mutating the array.
If you want to be sure that the returned array is not mutable, you could declare the property as in your original example, and then roll your own accessor:
- (NSArray *)myArray { return [NSArray arrayWithArray:myArray]; }
Note that this would return an unretained NSArray. It would be up to the caller to take ownership of the object if it needed to persist.
You are seeing errors because XCode is now issuing warnings and errors for things it did not previously...
I would argue that it should be at most a warning to do what you are doing, I understand your attempt to present the array as immutable to the outside world but have it mutable inside the class. You may want to consider a different accessor with a different name, built to return the mutable array specifically.
It is still Objective-C 2.0; the compiler is just maybe a little updated with considering this kind of type changing an error. It pretty much should be an error. At least it should warn you that you likely don't mean what you wrote. Then you could cast stuff to make it not warn you, which you can't do with the #synthesize statement.
I just exactly pasted your code and a synthesize statement into my controller and I got no errors or warnings about it. It built fine. Now I set the base SDK to "Simulator 3.0", and the build to "Simulator 3.0 Debug". This project had started in the 2.2.1 SDK and I just installed the 3.0 SDK yesterday; Xcode is version 3.1.3.
Update: Oh I see that actually trying to set the property is where you get the error you mentioned.
self.myArray = [NSArray arrayWithObject:#"foo"];
Clearly you cannot #synthesize this behavior and must write your own accessors.
- (NSArray*)myArray {
return [NSArray arrayWithArray:myArray];
}
- (void)setMyArray:(NSArray*) pMyArray {
myArray = [NSMutableArray arrayWithArray:pMyArray];
}
Filling in these accessors, did not make the message go away, so I had to change the access to:
[self setMyArray:[NSArray arrayWithObject:#"foo"]];
Using the above syntax without custom accessors also did not work.
PS Wow, is anyone else annoyed that you can neither copy message bubbles, or the text in the build results window?
So this is really to do with the #synthesize call that is not happy about exposing a NSMutableArray as an NSArray - why not just implement the getMethod.
Actually thinking about it it must be the set method that is not happy - you wouldn't be able to set an NSArray into an NSMutableArray.
Your questions were:
Is anyone aware of changes to objective-c between OS 2.2.1 and 3.0?
Is there any documentation for these changes?
The definitive answers are:
1) There were no intentional changes to the language specification, but the compiler and other developer tools changed. Chris and his coworkers are the experts on those changes.
2) Probably not, because any changes were unintentional or made to better match behavior with the documentation.
You shouldn't be so quick to dismiss Chris' answer as "a guess." Chris works on Apple's developer tools. You might get another answer you like more, but you won't be getting a more expert answer.