I have to perform a selector by name on a Class (not an instance) and use its return value:
id obj = [objClass performSelector:NSSelectorFromString(methodName) withObject:p1];
The selector creates a new instance of the Class. I need to use the returned instance. Obviously I get the usual performSelector may cause a leak because its selector is unknown warning since this project is compiled with ARC.
If I understand correctly (from the answers here and others), in this instance the performSelector will cause a leak (do correct me if I'm wrong, then I could just disable the warning and be done with it). The selectors are implemented as follows:
+ (id) objectWithFile:(NSString*)p1
{
return [NSKeyedUnarchiver unarchiveObjectWithFile:p1];
}
What are my options when I have to use selector from string and the selector creates and returns a new instance of the object?
I considered NSInvocation but its getReturnValue method requires me to provide my own allocated buffer in which the return value is stored. I'm not sure if this even works with ARC and class methods, or whether I simply have to __bridge_transfer cast the malloc'ed return value buffer to id and that's all there is to it.
objectWithFile: is not a method of the "alloc, copy, init, mutableCopy, and new family"
and therefore is
a "Unretained return values" method in the sense of the "Clang/ARC documentation":
A method or function which returns a retainable object type but does
not return a retained value must ensure that the object is still valid
across the return boundary.
...
In the worst case, this may involve an autorelease, but callers must
not assume that the value is actually in the autorelease pool.
So no matter what you do inside the method, the caller does not have to release the
returned object.
Therefore I don't think that you have a memory leak in your code.
Related
Now i have had this problem clouding my mind for quite sometime and i really need someone to clarify this for me.
1) what is a unique identifier that causes the init method to return a different object other than the one you were initially trying to allocate with the call?
.. What should you do in such a case?
2) When a designated initializer from one class assuming that class has more than one method, invokes the designated initializer in its parent class consequently invoking NSObject's init method; what exactly is happening when the parent class init method is invoked? what is "self" in that method explicitly referencing to, as well as the "self" returned from its root class?
Maybe this will answer your questions:
An init method is just a method like any other, there is nothing special about them per se;
Method parameters are local variables which are assigned an initial value, that value being the one given in the call;
self is a hidden method parameter, a value for it is passed in the call as with all other parameters;
The result of the method is implicitly marked with the ns_returns_retained attribute; and finally
The self parameter is implicitly marked with the ns_consumed attribute.
The attributes mentioned effect how ARC manages the references returned (ns_returns_retained) by, or passed to (ns_consumes), a method. These attributes can be explicitly applied to any method.
The attribute ns_returns_retained is applied implicitly to methods in the alloc, copy, init, mutableCopy, and new families; while ns_consumes is implicitly applied to the hidden self parameter of init methods.
The ns_consumes attribute is the only "unusual" feature of init methods. It tells ARC that the method being called takes ownership of the passed object reference, and hence is responsible for releasing it when required. So in the common statement found in init methods, a call to the superclass init method:
self = [super init];
the current reference stored in self is passed to the called method along with the callers ownership of that reference. When the result of the call is assigned back to self ARC does not need to relinquish ownership (aka "release") the old reference stored there - ownership was already passed to the called method - or take ownership (aka "retain") of the new reference - as the called transfers its ownership back to the caller.
The above allows an init method to return a different reference than the one it was passed, and releasing the one it was passed. This feature is not commonly used in user classes but a number of common system classes, e.g. NSString and NSNumber, take advantage to reduce the number of objects needed.
The above sounds more complicated than it is! If you have specific questions then ask new specific questions as #MichaelDautermann suggests in the comments.
HTH
Addendum
In response to comments maybe the following will help. All code typed directly on an iPad, expect errors!
How does the following method work?
- (NSString *) doSomething:(NSString *)aLocal
{
aLocal = [super aLocal];
return aLocal;
}
In the call:
NSString *someResult = [someObjectRef doSomething:someLocalVariable];
where someObjectRef is a variable holding a reference to an object that declares the above method, and someLocalVariable holds a reference to a string.
In outline it is:
a new method invocation is created along with its local variable aLocal
the reference stored in the callers someLocalVariable is copied (it's value not the object it references) and stored in aLocal
the statements of the method are executed
the first statement is a call to the same method implemented in the super class, the value of the reference in aLocal is passed to this method, and the reference returned by the call is stored into aLocal - replacing the reference previously stored there.
the second statement returns the value of the reference stored in aLocal as the method result, and that reference is stored into the caller's someLocalVariable.
None of that should be surprising, and the reference return is probably not the reference passed in (it could be, we've no idea what the inherited doSomething method does, it may just return what it was passed).
Now all you have to understand is that self is an implicitly passed parameter. What that means is the above method is effectively declared as:
- (NSString *) doSomething:(NSString *)aLocal selfRef:(instancetype)self
and Objective-C automatically supplies the reference passed as selfRef and stored into the method's local variable self.
Finally changing the name of doSomething to, say, initAndDoSomething changes the way ARC automatically handles the references passed as self and the one returned to ensure no unwanted objects get left lying around - this is done by implicitly adding the attributes mentioned in the original answer.
That's it, init methods are just methods. Don't think of them as special, it inflates their ego ;-)
HTH
I am having problem with understanding one concept of memory managment, because I am new to objective C. For instance lets say I have a class Bar and Foo.
in main function I call:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo retain];
[foo callMethod];
[foo release];
I know this is right way to do it. But why do we have to retain it after we get it from another object, does not this mean returning object has retain count 0 ? so we have to reatin it to count 1 to use it? but if it has reatin count 0, how do we know it is still there. We can assume since it is the next line that increment retain count that the object memory wont be realocated, but what if we have multi-threading program?
When an class method returns an object, it will autorelease it so you don't have to bother; typically:
- (Foo *)getFoo
{
return [[_foo retain] autorelease];
}
If you are only using foo for the lifetime of the calling method you don't need to retain it, as it won't be autoreleased until next time through the run loop, so your code should actually be:
Foo *foo = [bar getFoo]; //In my bar method I return foo
[foo callMethod];
If, however, you want to hold foo for a while, outside the scope of the calling method, you need to retain it and then release it sometime later.
One more thing; the convention for getter method names is simply "name", so your setter should be setFoo and your getter would be foo. Keeping to the naming conventions is a good idea as it lets you know what a method does, in say 7 months time, and tools like static analysis understand the conventions.
The method getFoo doesn't return an object with a 0 retain count. It returns an object with a +0 retain count which means that:
the object's retain count is not null (otherwise, the object wouldn't exist)
and the retain count wasn't altered by the invocation of the method, or if it was, it was in a balanced way (with as many release/autorelease as retain/alloc/new/copy).
Thus the lifetime of the object entirely depends on where and how it is retained. We don't know how long the object will be valid as any method invocation could release the object.
For example, let's consider the following code:
id anObject = [anArray objectAtIndex:0];
[anArray removeObjectAtIndex:0];
The object anObject isn't retained any more by the array as we removed it. Therefore it may have been destructed (but maybe it wasn't because it is still used somewhere else).
Generally, when getting an object from a method (other that alloc, copy, new or retain), we can assume that:
either the object was retained then autoreleased,
either the object is retained by the object that returned it.
So we know the object foo is valid until we return from the current method/function or we invoke a method/function that alter the state of the object bar, whichever comes first. After that, it may have been destructed.
So in your case, you can safely omit the retain/release pair.
However, it is very difficult to guaranty that an object doesn't get released unless we know the implementation of every method we invoke. Therefore, retaining (then releasing) every single object we get is the safer approach and that's what the compiler will do when you enable ARC (Automatic Reference Counting).
But that would require you to write a lot of retain/release and your code would become difficult to read, understand and maintain. Moreover, the more code you write, the more bugs you get (unless you never write bugs).
In conclusion, you don't need to retain an object unless you have a reason to suspect it could vanish otherwise.
I'm overriding - (BOOL) isEqual:(id)object in a custom class.
Out of the 4 choices, which are __weak, __strong, __autoreleasing, and __unsafe_unretained, which should I be using on the parameter for the isEqual: method signature?
I'm thinking this is where the problem is, since when I'm trying to add an instance of my class to a NSMutableDictionary, I'm getting an EXC_BAD_ACCESS(code=2, address=0x10) at the declaration of the method.
In other words, the line at which the debugger gets the EXC_BAD_ACCESS is:
- (BOOL) isEqual:(id __strong)object {
before any of the method body is executed.
The correct answer was "If you're getting bad access, then you're trying to read or write to an area that doesn't have what you think it has in it.", per #Dustin Rowland in the comments.
By default, ARC uses __strong, which means that the argument is held via a retain/release for the duration of its use inside the method. To lead to EXC_BAD_ACCESS, an object (either the argument itself, or any other object used in the method calls inside the isEqual: implementation) has to be over-released when accessing it. This cannot be fixed by changing the qualifier.
Sidenote: Be careful though by expecting to see anything to change when you change the qualifier. The compiler optimizations may decide that it is safe to skip some calls. For example, add the following code to a file and look at the assembly (Product -> Generate Output -> Assembly File) for Archiving (which uses -Os).
- (void)logObject:(id)o
{
NSLog(#"%#", o);
}
- (void)call
{
id o = [[NSObject alloc] init];
[self logObject:o];
}
Although the parameter of logObject: is the default __strong, no retain/release is done in the assembly output. Changing the parameter of -logObject: to __strong, __weak, __unsafe_unretained or __autoreleasing gives exactly the same assembly output. If you duplicate the line with the NSLog however, the assembly code changes for the different type qualifiers.
I'm learning how to program, and starting off with Objective C. I'm trying to understand exactly what happens when an object is allocated from within a method.
-(Fraction *) add: (Fraction *) f
{ //'result' will store the result of the addition
Fraction *result = [[Fraction alloc]init];
result.numerator = (numerator*f.denominator + denominator*f.numerator);
result.denominator = denominator*f.denominator;
[result reduce];
return result;
}
I understand that I can create an object to store 'result' in when it is returned,
tempStorageObject = [aFraction add: bFraction];
and that i am then responsible for releasing it, but what happens when I don't store it, as in:
[aFraction add: bFraction];
NSLog(#"%i/%i", result.numerator, result.denominator); //result object not declared in main
I am told that I have an undeclared identifier. I get that, but what exactly happens to 'result' after using my 'add' method. Where does it go? Shouldn't I be able to access its variables since it was created and returned in the method? Obviously not, but I'm not clear on why. I've tried re-reading my book and searching this forum but I can't find a clear answer. Thanks. (First post)
Four different things:
Properties
Local variables
Function return values
Heap storage
"I get that, but what exactly happens to 'result' after using my 'add' method. Where does it go?"
It's a local variable. It's gone.
"Shouldn't I be able to access its variables"
Seeing your comment, it looks like you mean access by dot notation. No, dot notation is for properties.
"since it was created"
Dot notation does not give you access to local variables.
"and returned in the method?"
Dot notation does not give you access to function return values.
All of the first three things are pointers, when they refer to objects. The fourth thing is what they point to. When you do alloc, you create an object in heap storage. You then have instance variables, properties, local variables, and function return values refer to the heap storage. In a way you think of them as being the same thing as the object in heap storage. Syntactic sugar like dot notation helps you do that. Your object will last, but in this case the different variables that refer to it are limited in scope and come and go.
When you call alloc, an object is created on the heap.
When you assign it to result, result now has the same object.
When you return result, the local variable result no longer exists, the return value temporarily holds the same object, and the object still exists in the heap.
4a. When you assign the function result to tempStorageObject, another local variable (I guess), the function result goes away. It existed only temporarily to pass a value from inside the function to out. tempStorageObject now holds the object, and the object still exists in the heap.
4b. Instead if you don't assign the function result to anything, then the function result still goes away. But the object still exists on the heap. You have a problem. You have an object on the heap, but you can't refer to it directly there (unless you are good at guessing its address). Without being able to refer to it, you can't get it off the heap, which will be a major problem if you do that kind of thing over and over. The heap will start to get full with objects you can't get rid of and you'll run out of memory. That's what's called a leak.
The correct thing to do in this case is to return [result autorelease]. When you call [something autorelease], it adds "something" to an "autorelease pool" and then returns the same something.
You call alloc and create an object on the heap. Its retain count starts at 1.
You assign it to result, a local variable. Result has the object and it's on the heap.
[result autorelease]. result has the object, it's in an autorelease pool, and it's on the heap.
return that. result is gone, the return value has the object, it's in the autorelease pool, and it's on the heap.
5a. Assign the return value to tempStorageObject. The return value is gone, tempStorageObject has the object, it's in an autorelease pool, and it's on the heap.
6a. You leave the scope of tempStorageObject. tempStorage object is gone. The object is in an autorelease pool and on the heap.
5b. You don't assign the function result to anything. The function result is gone. The object is in an autorelease pool and on the heap.
7ab. The autorelease pool is drained. That is usually done from code in the main run loop provided by the system library, but you can do it yourself if you know how. All the objects in the autorelease pool, including the one we're paying attention to, are sent a release message. The object's retain count goes to 0.
8ab. With a retain count of 0, the object is removed from the heap. The object is in the autorelease pool.
9ab. The second thing drain does is remove all the objects from the pool. Now the object doesn't exist anywhere anymore.
You said you are familiar with release, so I just say you should use autorelease keyword, which releases the allocated object when no more code blocks need it, check document below, from Apple:
Memory Management Programming
The scope of alloc is global: once you have allocated an object, there is room for it in memory and that memory will remain allocated until the release count hits zero (or the app is terminated). Until then, the object will still exist.
The scope of a variable is much shorter. In your example 'result' goes out of scope right at the end of the method 'add'. But that variable is just a name, a reference to an object. So whoever is calling add, should make sure to do something with the returned object. Otherwise there is no more variable referring to the object and so it can not be released.
How would I dealloc a boolean value?
Deallocing it this way below gives me a warning: Incompatible pointer to integer conversion assigning to 'BOOL' (aka 'signed char') from 'void *'
- (void)dealloc {
self.booleanVar = nil;
[super dealloc];
}
Perhaps I should clarify, this is from a simple class inherited from NSObject.
I'm using the self.var = nil pattern that you see in Cocoa Touch classes. Let's say if it was an NSString* instead should I use self.var = nil or [var release] in the deallocmethod? I'm a little confused here.
You don't need to do it. It is not an object. This also explains the warning, as you're trying to assign a nil pointer (that's a NULL for objects basically) to a non-object.
Regarding your second question, yes. You can think of primitive variables as being part of the object, so when it's deallocated the vars will not exist anymore.
But when you have a NSString * in an object, it's just a pointer to another object. If you dealloc the former, the pointer will be deleted, not the NSString. No one might point to it, it's kind of lost in the air, occupying memory. So, before deleting the pointer, if you won't need the object anymore, you send it a release message. That's done in the dealloc method, since it's called to "delete" and object and thus is a good place to delete also every other object that has no use anymore.
You dont need to dealloc a BOOL, since BOOLs are really just a byte, which is a primitive data type. You only need to dealloc objects which have been allocated to memory.
First of all, if booleanVar is just a plain BOOL value, as in it is declared like so:
BOOL booleanVar;
then you do not need to free up any memory associated with it, since that memory is allocated and freed when the class that holds it is allocated and deallocated. So no code for booleanVar in dealloc will be fine.
However, if you are talking about a pointer for a BOOL, defined like so:
BOOL *booleanVar;
and what you want is to set this variable to a non-value, you should set it equal to NULL instead of nil, since NULL is for value pointers and nil is for object pointers (see: NULL vs nil in Objective-C).
However, if what you want is to free up the memory that the BOOL pointer points to, allocated with malloc or realloc, etc, then try the free() C function (see: http://www.cplusplus.com/reference/clibrary/cstdlib/free/).
What would really clear all this up is if you showed us the property declaration for booleanVar in the class interface, which would tell us exactly what you want to do and you would get an answer with complete certitude.