Today I was at interview and was asked a question:
Generate setter and getter by hands for proper declaration using manual reference counting:
#interface SomeClass : NSObject
{
NSMutableArray* _array;
}
#property (copy) NSArray* array;
#end
My answer was:
- (NSArray *)array
{
#syncronized (self)
{
return [_array copy];
}
}
- (void)setArray:(NSArray *)array
{
#synchronized (self)
{
if (_array != array)
{
[_array release];
_array = [array mutableCopy];
[_array retain]
}
}
}
I never worked using MRC so not sure about correctness of an answer. Please help me to correct this code with description!
I am the author of one of the linked topics and I think now I understand MRC enough to write this answer here:
1) You're obviously leaking the copy in the getter (see it also in the comments) - so it should be balanced by corresponding autorelease call.
Also note, that this copy inside your getter is done because of you need to return immutable object, not because of getters for #properties declared with (copy) require you to do so!
2) Your setter should not retain after mutableCopy, since mutableCopy already does +1 for you.
See the following quotes from Advanced Memory Management Programming Guide
Basic Memory Management Rules.
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
And
Ownership Policy Is Implemented Using Retain Counts
The ownership policy is implemented through reference counting—typically called “retain count” after the retain method. Each object has a retain count.
When you create an object, it has a retain count of 1.
3) In my topic's comments #robmayoff shared the link to open source implementation of runtime: reallySetProperty in objc-accessors.mm with the following reasoning behind it:
The nonatomic retain and copy setters unfortunately have an unnecessary race condition. If, on thread 1, the setter releases _count, and on thread 2 the getter accesses _count before thread 1 has set _count = [count retain], thread 2 may access a deallocated object. Always store the new value in _count before releasing the old value. The real accessor in the Objective-C runtime does it correctly. See reallySetProperty in objc-accessors.mm. – rob mayoff
4) You example is also missing dealloc since you were to write it under MRC.
5) [IMO, maybe subjective] Since your setter is creating copies of array argument, you don't need to have this if (_array != array) check since the task of (copy) setter is, I believe, to produce copies of what is passed, so I think this is may be omitted.
Having these points in mind I would write your example like the following:
- (NSArray *)array
{
id array;
#synchronized (self)
{
array = [_array copy];
}
return [array autorelease];
}
- (void)setArray:(NSArray *)array
{
id oldValue;
#synchronized (self)
{
oldValue = _array;
_array = [array mutableCopy];
}
[oldValue release];
}
- (void)dealloc {
[_array release];
[super dealloc];
}
In answer to your question in the comments:
Is it normal and really can be used in the daily practice?
I would say, that it can be used in a daily practice with the following additional considerations:
1) You should move you ivar declaration into a private category #interface SomeClass () be it inside your .m file or a private class extension.
2) You should make your getters/setters nonatomic since atomicity of this property is on your shoulders (you already do synchronized on your own in both setter and getter).
3) See also the setup from linked topic which omits ivar and uses second #property declaration. In your case it would look like this:
// .h
#interface SomeClass : NSObject
#property (nonatomic, strong, readonly) NSArray *array;
#end
// .m or private class extension
#interface SomeClass()
#property (nonatomic, strong) NSMutableArray *array;
#end
#implementation SomeClass
// and here your getters/setters
#end
This setup looks promising though I haven't really tested it for the case like yours.
P.S. Recently I did some research for this back-to-the-past Manual Reference Counting, let me share with you the following links which I found to be the best on this topic:
Advanced Memory Management Programming Guide (this is the MUST)
An In-depth Look At Manual Memory Management In Objective-C (this one too!)
What clang taught us about Objective-C properties
Memory and thread-safe custom property methods
Source code of objc runtime.
Related
I'm exposing a few properties from an Objective-C project to Swift (based on this repo), but have no experience in Objective-C, so I'm rather out of my depth here, so please bear with me.
I'm wondering how to correctly dealloc a nonnull property (or whether it's necessary at all!). I've provisionally dealloc'ed the nonnull property surface by setting it to null (in the same manner as is done for the nullable partOfSpeech). However, this prompts the following warning:
Null passed to a callee that requires a non-null argument
... so I wonder whether it's redundant. Is there anything I should do instead to handle my nonnull property, during the Node class's dealloc block?
Given the interface, node.h:
#interface Node : NSObject {
NSString *surface;
NSString *partOfSpeech;
}
#property (nonatomic, retain, nonnull) NSString *surface;
#property (nonatomic, retain, nullable) NSString *partOfSpeech;
- (nullable NSString *)partOfSpeech;
#end
... And the implementation, node.m:
#implementation Node
#synthesize surface;
#synthesize partOfSpeech;
// surface is assumed to be set post-initialisation.
- (void)setPartOfSpeech:(NSString *)value {
if (partOfSpeech) [partOfSpeech release];
partOfSpeech = value ? [value retain] : nil;
}
- (NSString *)partOfSpeech {
if (!features || [features count] < 1) return nil;
return [features objectAtIndex:0];
}
- (void)dealloc {
// WARNING: "Null passed to a callee that requires a non-null argument"
self.surface = nil;
self.partOfSpeech = nil;
[super dealloc];
}
#end
... And given that a Node's lifecycle is like this:
Node *newNode = [Node new];
newNode.surface = [[[NSString alloc] initWithBytes:node->surface length:node->length encoding:NSUTF8StringEncoding] autorelease];
// ... Do stuff with newNode (eg. add to array of Node)...
[newNode release];
First: The compiler can automatically synthesize instance variables and
setters/getters for your properties. So your interface should be just
// Node.h
#interface Node : NSObject
#property (nonatomic, retain, nonnull) NSString *surface;
#property (nonatomic, retain, nullable) NSString *partOfSpeech;
#end
and no #synthesize statements are needed in the implementation file.
The compiler will automatically create instance variables
_surface and _partOfSpeech, and also create accessor methods
- (NSString *) surface;
- (void)setSurface:(NSString *)value;
- (NSString *)partOfSpeech;
- (void)setPartOfSpeech:(NSString *)value;
which do "the right thing", with or without ARC. You can override
those methods if you want to implement some custom logic, but you don't have to implement a standard setter like your setPartOfSpeech.
If you use ARC (automatic reference counting) then that is all,
nothing more is needed. And
I would really recommend to do so. The compiler inserts the required retain/release calls at compile time, and is quite clever in avoiding
unnecessary calls. See for example
Confirmed: Objective-C ARC is slow. Don’t use it! (sarcasm off)
about some comparisons. With MRC (manual reference counting), your code might even be slower, or
have memory leaks.
But to answer your question: With MRC you have to release the
instance variables in dealloc
- (void)dealloc {
[_surface release];
[_partOfSpeech release];
[super dealloc];
}
as explained in Memory Management Policy in the "Advanced Memory Management Programming Guide".
You should not use the accessor methods in dealloc as in your
self.surface = nil;
self.partOfSpeech = nil;
see Don’t Use Accessor Methods in Initializer Methods and dealloc.
If you are using manual memory management you can just release the object stored in the properties backing variable. As you've named the backing variable the same as the property use the -> to clearly reference the backing variable:
[self->surface release];
Or if you want to do this with assignment just assign the empty string literal:
self.surface = #"";
The string literal is created at compile time, lives throughout the program execution, and takes up very little space. The assignment will caused the release (and deallocation if the reference count reaches zero) of the previous value in the property, just like assigning nil (or any other value).
HTH
What difference does it make in memory management to define a variable as a property? For instance:
#interface foo {
NSString *theStr;
}
#end
#implementation foo
- (void)bar {
NSLog(theStr);
}
#end
Versus:
#interface foo {
NSString *theStr;
}
#property(retain) NSString *theStr;
#end
#implementation foo
#synthesize theStr;
- (void)bar {
NSLog(theStr);
}
#end
It seems like the first is autoreleased or something similar, while the second is retained throughout the life of the class. Is that the case, or what is the difference?
If you define a variable just in the interface without defining it as a property (as in your first example) means that you'll have to take care of everything related to memory management yourself. Assigning something to that variable will not retain it automatically, not will setting the variable to something else release the previous value.
Defining it as a property creates getter and setter methods under the hood. Most importantly, if you use it with the "retain" keyword, your setter method will retain the new value (and release the old one if there was one).
Note that the setter method will only be invoked if you use the dot notation, e.g., self.myStr = #"new string", or the method call, e.g., [self setMyStr:#"new string"]. If you just call myStr = #"new string" the setter method will not be called and you need to release the old value yourself and retain the new one.
I don't think the first case shows an autoreleased object, it would all depend on how you managed the creation and the destruction of that particular object. If for instance when you create that object you call:
//This string will indeed be autoreleased
theStr=[NSString stringWithString:#"Jibber jabber"];
//Or even
theStr=#"Jibber jabber";
But you have to take charge of the memory management if you create it in the following way:
//Manage my memory
theStr=[[NSString alloc] init];
//You have to release this property on the dealloc method
-(void)dealloc{
[theStr release];
[super dealloc];
}
On your second example, you create a setter and a getter method for the property theStr and by adding the nonatomic attribute, you make your property not thread safety, meaning that a thread can begin to modify your property while another one is already editing it. And by setting the retain attribute to your property, the setter method will be synthesized the following way:
- (void) setTheStr:(NSString *) newString {
[newString retain];
[theStr release];
theStr = newSupervisor;
}
You can consult more about this in one of my favorite books, Learning Objective-C 2.0 in chapter 12.
I'm not sure I understood how alloc and retain work.
Recently I discovered that the NSString properties were not retained and I had to add [myString copy] when I set them. Which makes me wonder if I misunderstood the whole way of using retain/alloc
Please, may someone tell me if I'm doing it correctly? I read a lot and had a look on open source projects, this let me thing that I may have been wrong since the beginning.
Here is my way of doing it:
/**** VIEW.h *****/
#import "MyClass.h"
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
#property (nonatomic, retain) MyClass *myObject;
- (void)defineObject;
#end
.
/**** VIEW.m *****/
#import "VIEW.h"
#implementation MyViewController
#dynamic myObject;
- (void)viewDidLoad
{
[super viewDidLoad];
[self defineObject];
NSLog(#"My object's name is: %#", myObject.name);
}
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
.
/**** MyClass.h *****/
#interface MyClass : NSObject {
//not sure if this line is still necessary
NSString *name;
}
#property (nonatomic, retain) NSString *name;
- (id)initPersonalised;
- (void)setName:(NSString *)name;
- (NSString *)name;
#end
.
/**** MyClass.m *****/
#import "MyClass.h"
#implementation MyClass
#dynamic name;
(id)initPersonalised{
self = [super init];
name = #"Undefined";
}
- (void)setName:(NSString *)name{
self.name = [name copy];
}
- (NSString *)name{
return [self.name copy];
}
#end
I hope you can bring a bit of light, after months of programming this way, I'm less and less sure of doing it well.
This is indeed a topic that every Objective C programmer stumbles upon. There are a few things one needs to know:
Instance variable vs. property access
Within MyViewController,
myObject = xxx;
and
self.myObject = xxx;
are two different things. The first directly assigns to the instance variable and does neither release to old referenced insance nor retain the newly assigned instance. The latter one uses the property setter and thus releases the old and retains the new value.
Deallocation
Even when you have declared an implemented a property that takes care of retaining and releases the values, it won't take care of deallocation when your object (MyViewController in your case) is released. So you must explicitly release it in dealloc:
-(void) dealloc {
[myObject release];
[super dealloc];
}
Now to your code:
The snippet:
myObject = [[MyClass alloc] initPersonalised];
is perfectly okay. When you create an object, you use the pair of alloc and initXXX. The always create an instance with the reference count set to 1. So by directly assigning it to the instance variable, you create a clean constellation. I don't see no other way of creating the instance.
In MyClass you could use #synthesize name instead of #dynamic. Then the compiler would implement name and setName: automatically and you wouldn't need to do it yourself.
Finally, your missing dealloc.
Update:
If you use:
self.myObject = [[MyClass alloc] initPersonalised];
then you have a memory leak because initPesonalised sets the reference count to 1 and the setter of myObject increases it to two. If you want to use the setter, then I has to be:
MyClass* mo = [[MyClass alloc] initPersonalised];
self.myObject = [[MyClass alloc] initPersonalised];
[mo release];
It would be different if you weren't using initXXX to create a new instance. The class NSString for example has many methods called stringXXX, which create a new instance (or return a shared one) that has (conceptually) a reference count of 1 that will later automatically decreased by one. Then you better use the setter:
self.name = [NSString stringWithFormat: #"instance %d", cnt];
If you want to use copy instead of retain for your string property (which is good practice), then you can simply declare your property like this:
#property (nonatomic, copy) NSString *name;
When you then use #synthesize to implement the getter and setter, the compiler will generate them using copy instead of retain.
And NSString *name; is necessary even if you use #property and/or #synthesize to implement the property.
Alloc and init are methods that always go hand-in-hand. alloc allocates space for your object, and init initializes your object to some value. When you call alloc, you are responsible for freeing that object later. If you call copy, you are also responsible for releasing that object later. It's considered good practice to always initialize your objects right after you allocate them.
Now, to answer the questions I found in your code.
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
So is that line necessary? That depends. Does it make sense that your object has a MyClass as a property? This is a question only you can answer based on your design. I recommend you to study Object-Oriented Programming in more depth.
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
Not necessarily. You are just providing a pointer to an object of the specified kind. The moment you set your property, depending on the property modifiers, your class will know what to do with MyObject.
In that way, there's no need to call [yourObject copy]. In this way your properties will be copied instead of being retained. Just don't forget to release it later in your -dealloc method, like you would with retain properties.
All in all, this is what I recommend you to study a bit more:
Object-Oriented Programming (not related to your issue, but I can tell you are not comfortable using it. Objective-C is heavily object oriented, so you want to understand OOP).
iOS Memory Management.
You can have a look at the Memory Management Guide. It will help you to better understand the alloc & retain concepts; hope this helps you.
I'm a objective c newbie, and i'm having a bit of problems with memory management, I've read the apple's memory management policies, however i need a bit of clarification here, this is pretty simple i guess, but i would like to ask you if I'm right:
Given this property:
#interface Test : NSObject {
NSArray *property1;
}
#property (nonatomic,retain) NSArray* property1;
#end
...
//And its implementation:
#implementation Test
#synthetize property1;
-(id) init {
if (self=[super init]) {
self.property1=[[[NSArray alloc] initWithCapacity:5] autorelease];
}
return self;
}
-(void) dealloc {
[super dealloc];
[property1 release];
}
#end
Is it right to issue an Autorelease message to the allocated object in the init method?, i do this cause in apple's document, says that every allocated object should be released by the developer, then, I think, alloc sets retain count to 1, then the property (nonatomic, retain) adds 1, so retain==2, then autorelease substracts 1, and when the dealloc method is called, property1 is released and retain count==0, am I right?
You have your memory management right, though Apple (and a lot of other people) generally recommend not using accessors in your initialization methods because accessors can have side effects beyond simply setting an instance variable that your class might not be set up to handle yet. And in that case, you wouldn't want to autorelease since you'd want ownership of the object.
one side note: in your dealloc, you need to release the property before calling [super dealloc], because [super dealloc] eventually deallocates the memory of the object, which includes the memory containing the property1 variable, so it is invalid to refer to that variable after you call [super dealloc]. It should be:
-(void) dealloc {
[property1 release];
[super dealloc];
}
One of the nice things about using properties is that you can encapsulate all of your "releasing" behavior regardless of whether your property is set to retain, copy, assign, or whatever by just doing this:
self.property1 = nil;
Personally I've gotten in the habit of setting all properties to nil (using self.property, not just accessing the member variable directly) in dealloc so that even if I change how the memory management works for the member variable it works correctly.
I'm working on an iPhone application. I have an object of class Row that needs to release numerous objects of the class Block. Every Block currently has a property that retains an instance variable of class Row.
#interface Block : UIImageView {
Row *yCoord;
}
#property (nonatomic,retain) Row *yCoord;
#end
Every Row contains an NSMutableArray of these Blocks.
#interface Row : NSObject {
NSMutableArray *blocks;
}
-(void)addBlock:(Block*)aBlock;
#end
#implementation Row
-(void)addBlock:(Block*)aBlock {
[blocks addObject:aBlock];
aBlock.yCoord = self;
}
#end
I understand that this is a circular reference. Apple's documentation states that in order to deallocate an object with a circular reference I need a weak reference instead of a strong reference (a retain property), but it doesn't follow through and explain how exactly I go about doing so. I plan to release and dealloc all Blocks within a Row as well as the Row itself simultaneously. How do I set up a weak reference within each of my Blocks to their "parent" Row?
Edit: Since the asker clarified he's not using garbage collection (iPhone currently does not support it), my advice is to avoid cycles by having only one of the objects retain the other, just as you would do with a delegate. When using properties, use "assign" instead of "retain" to achieve this. For example:
#property (nonatomic,assign) Row *yCoord;
The rest of my answer answer relates to "weak references" in terms of Objective-C 2.0 and GC.
When you're working with garbage collection (10.5+), a weak reference is created by prefixing a variable declaration with __weak. When you assign to that variable, the GC (if enabled) keeps track of the reference and will zero it out for you automatically if all strong references to the referenced object disappear. (If GC is not enabled, the __weak attribute is ignored.)
Thus, you can safely modify the above answer to play nicer with garbage collection (currently on 10.5+, and perhaps someday on iPhone) as follows: (See the related Apple docs.)
#property (nonatomic,assign) __weak Row *yCoord;
To quote Chris Hanson (where you can find more detailed information):
"By prefixing an instance variable declaration with __weak, you tell the garbage collector that if it's the only reference to an object that the object should be considered collectable."
I'd clarify that by saying "if there are no non-weak references to an object". As soon as the last strong reference is removed, the object may be collected, and all weak references will be zeroed automatically.
Note: This isn't directly related to creating weak references, but there is also a __strong attribute, but since Objective-C object variables are strong references by default, it is generally used only for raw C pointers to things like structs or primitives that the Garbage Collector will not treat as roots, and will be collected from under you if you don't declare them as strong. (Whereas the lack of __weak can cause retain cycles and memory leaks, the lack of __strong can result in memory stomping and really strange and insidious bugs that occur non-deterministically and can be quite difficult to track down.)
Just change it to assign instead of retain, no more circular references.
#interface Block : UIImageView {
Row *yCoord;
}
#property (nonatomic,assign) Row *yCoord;
#end
A weak reference is simply an assignment (unless you're talking about Garbage Collection which is a whole separate can of worms, but does not suffer from retain cycles).
Normally, in Cocoa, Row would retain the Block objects (by including them in the NSMutableArray), but Block would not retain Row, each would simply store it in an ivar (with an "assign" property).
As long as Row is careful to release each Block before it is deallocated (ie, its dealloc should release the NSMutableArray which will release the Blocks as long as no one else has any pointers to them) then everything will be deallocated as appropriate.
You can also take the precaution of zeroing the row reference from Blocks before removing the entiries from the array, something like:
- (void) dealloc {
for (Block* b in _blocks) {
b.row = nil;
}
[_blocks release];
[super dealloc];
}
where _blocks is the ivar referenced by the blocks property.
Using assign to create weak references can be unsafe in a multithreaded system, particularly when either object can be retained by a third object, and then used to dereference the other object.
Fortunately, this is often a problem of hierarchy, and the object containing the weak reference only cares about the object it refers to for the referred-to object's lifetime. This is the usual situation with a Superior<->Subordinate relationship.
I think that the case in the OP's comment maps to this, with Row = Superior, Block = Subordinate.
In this case, I would use a handle to refer to the Superior from the Subordinate:
// Superior.h
#class Superior;
#interface SuperiorHandle : NSObject {
#private
Superior* superior_;
}
// note the deliberate avoidance of "nonatomic"
#property (readonly) Superior *superior;
#end
#interface Superior : NSObject {
#private
SuperiorHandle *handle_;
// add one or more references to Subordinate instances
}
// note the deliberate avoidance of "nonatomic"
#property (readonly) SuperiorHandle *handle;
#end
// Superior.m
#import "Superior.h"
#implementation SuperiorHandle
#synthesize
superior = superior_;
- (id)initWithSuperior:(Superior *)superior {
if ((self = [super init])) {
superior_ = superior; // weak reference
}
}
- (void)invalidate {
#synchronized (self) {
superior_ = nil;
}
}
- (Superior *)superior {
#synchronized (self) {
// retain and autorelease is required to prevent dealloc before we're ready, thanks to AndroidDev for pointing out this mistake
return [[superior_ retain] autorelease];
}
}
#end
#implementation Superior
#synthesize
handle = handle_;
- (id)init {
if ((self = [super init])) {
handle_ = [[SuperiorHandle alloc] initWithSuperior:self];
}
return self;
}
- (void)dealloc {
[handle_ invalidate];
[handle_ release];
[super dealloc];
}
#end
// Subordinate.h
#class Superior;
#class SuperiorHandle;
#interface Subordinate : NSObject {
#private
SuperiorHandle *superior_handle_;
}
#property (readonly) Superior *superior;
#end
// Subordinate.m
#import "Subordinate.h"
#import "Superior.h"
#implementation Subordinate
// no synthesize this time, superior's implementation is special
- (id)initWithSuperior:(Superior *)superior {
if ((self = [super init])) {
superior_handle_ = [superior.handle retain];
}
return self;
}
- (void)dealloc {
[superior_handle_ release];
[super dealloc];
}
- (Superior *)superior {
#synchronized (superior_handle_) {
return superior_handle_.superior;
}
}
#end
Some advantages:
It's thread safe. There is no way you can have the weak reference contained in Subordinate become an invalid pointer. It may become nil but that is OK.
Only the objects themselves need to know about the embedded weak reference. All other objects can treat Subordinate as if it has a regular reference to Superior.